Android 常见布局全解之线性布局

Android常见布局解析

本文概述:

  • 本文为Android布局系列文章第一篇,本系列以常见Android布局为主题进行全面深入的探讨;

  • 本文重点:线性布局基本使用,线性布局中权重使用,特殊情况下子View宽/高计算公式,如何通过代码设置控件属性;线性布局分割线的两种设置方法;线性布局的局限性(引出相对布局)

  • 参考链接:

常见布局种类:

1655947861101.png

布局细节:

  • 布局可以嵌套布局:

    • 所有的UI元素都是通过View与ViewGroup构建的。而ViewGroup可作为容器盛装界面中的控件,可包含普通的View控件,也可包含ViewGroup,即ViewGroup可嵌套ViewGroup.
  • View视图嵌套示例

1655948171812.png

  • 从上面的层次结构图,可以看出这些布局都直接或者间接继承自ViewGroup,因此它们也支持在ViewGroup中定义的属性,这些属性可以看作是布局的通用属性。

    • 在View里面有个surfaceView,这个东西就不是继承自View的,那么它就不具有View的共有属性,但是也不受因继承自View而带来的限制

    • 补充:surfaceView

      • surfaceView效率高使用于动画效果较多的地方,其内部拥有独立的surface(不共享的)

        • 内部存在双缓冲模型,使用两张Canvas进行处理
        • 其内部mSurface不属于View体系,因此不受ViewRootImpl的影响,但其也不具备View系中的缩放等功能,并且surfaceView不能放在ViewGroup内
      • View绘图效率不高,适用于动画较少

布局共性:

1655949596099.png

线性布局:LinearLayout

概述:

此布局方式使用频繁,由orientation可分为水平线性(内部元素水平摆放)与垂直线性(内部元素垂直摆放)

1655949818718.png

整体思维导图:

1655952825824.png

线性布局重要属性:权重

定义与使用细节:

  • 定义:定义了子View在父容器内所占宽/高比例

  • 使用细节:将子View的宽/高设置为0dp,根据业务需要设置gravity属性(整数值A)

    • 当前子View所在宽/高(value)计算公式:value = (父容器宽/高)/所有子View权重 * 当前子View所在权重

具体示例一:基本使用

  • 业务需求:线性布局A包含线性布局B、线性布局C,水平摆放且B、C各占A的一半

  • 实现效果:

1655954088455.png

  • 细节:

    • 若需要指定某一子LinearLayout id属性,那么需要指定其orientation 属性

      • 为什么会这样:先mark,后面再来查资料

        • 猜测:可能与布局解析流程有关,今天晚上回去整理setContentView流程的时候记到看一下这个东西
  • 代码示例:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="ui.LineraLayoutBasic"
        android:orientation="horizontal"
        android:id="@+id/layoutA">
    ​
        <LinearLayout
            android:id="@+id/layoutB"
            android:layout_width="0dp"
            android:layout_height="20dp"
            android:background="#ADFF2F"
            android:layout_weight="1"
            android:orientation="horizontal" />
    ​
    ​
        <LinearLayout
            android:id="@+id/layoutC"
            android:layout_width="0dp"
            android:layout_height="20dp"
            android:background="#DA70D6"
            android:layout_weight="2"
            android:orientation="horizontal" />
    ​
    ​
    </LinearLayout>
    

具体示例二:当子View均为(match_parent)引出权重计算方法

  • 业务需求:线性布局A以水平排列三个子线性布局B、C、D且子布局占比分为1:2:3

  • 代码效果:

1655955245630.png

  • 布局代码展示:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="ui.LineraLayoutBasic"
        android:orientation="horizontal"
        android:id="@+id/layoutA">
    ​
        <TextView
            android:layout_weight="1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="子线性布局A"
            android:textSize="35sp"
            android:background="#98FB98"
            />
        <TextView
            android:layout_weight="2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="子线性布局B"
            android:textSize="35sp"
            android:background="#FFFF00"
            />
        <TextView
            android:layout_weight="3"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="子线性布局C"
            android:textSize="35sp"
            android:background="#FF00FF"
            />
    </LinearLayout>
    
  • 出现问题:线性布局C消失了,并且线性布局A :线性布局B = 2 :1

    • 计算公式:

      1. 因为三个子线性布局均为match_parent--->意味着子View共需要3块屏幕,但实际上就只有一块

        • 那么 1 - 3 = -2
      2. 子View比例为:1:2:3

        • 计算线性布局A占比: 1 - 2 * (1/6) = 2/3
        • 计算线性布局B占比: 1 - 2 * (2/6) = 1/3
        • 计算线性布局C占比: 1 - 2 * (3/6) = 0/3
    • 备注:在日常开发中不会这样写,若需要以权重限定子view宽/高,需结合父容器orientation属性,设置0dp(ex:父容器水平摆放时,子view宽度设为0dp)

    • 为什么会出现这个问题?

具体示例三:通过 Java代码设置控件属性

  • 运行结果:可以观察到xml预设(1:1),实际运行时(2:1)

    1655964836209.png

  • Java 代码展示

    package ui;
    ​
    import androidx.appcompat.app.AppCompatActivity;
    ​
    import android.os.Bundle;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    ​
    import com.cdqiantuo.layoutest.R;
    ​
    public class LineraLayoutSuper extends AppCompatActivity {
    ​
        private TextView textViewA;
        private TextView textViewB;
    ​
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_linera_layout_super);
            textViewA = findViewById(R.id.textviewA);
            textViewB = findViewById(R.id.textviewB);
    ​
            //设置权重
            setWeight(textViewA,2);
            setWeight(textViewB,1);
    ​
        }
    ​
        public void setWeight(TextView textView,int weight){
            LinearLayout.LayoutParams text =new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,weight);
            textView.setLayoutParams(text);
            //此处我需要均分高度就在heignt处设0,1.0f即设置权重是1,页面还有其他一个控件,1:1高度就均分了
        }
    }
    

线性布局重要属性:分割线

定义与用途:

  • 常用于分割子View,使得界面美观

具体示例一:以view 标签充当子View分割

  • 业务需求:在线性布局中水平摆放两个控件,以view 标签作为二者分割符

  • 实现效果:

1655966370615.png

  • 代码展示:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="ui.LineraLayoutSuper"
        android:orientation="horizontal">
    ​
        <TextView
            android:text="TextView A"
            android:id="@+id/textviewA"
            android:layout_width="200dp"
            android:layout_height="match_parent"
            android:background="@color/white"/>
        
        <View
            android:layout_height="match_parent"
            android:layout_width="5px"
            android:background="#190C29"
            />
    ​
        <TextView
            android:text="TextView B"
            android:id="@+id/textviewB"
            android:layout_width="200dp"
            android:layout_height="match_parent"
            android:background="@color/white"/>
    ​
    </LinearLayout>
    

具体示例二:使用 LinearLayout的divider属性

  • 使用描述:实质上就是将图片充当分割线

    • 分割线图片:为了效果明显,将图片设置较大

1655966828765.png

  • 重要属性:设置父容器属性

    • 设置分割线图片路径

      android:dividerPadding="10dp"
      
    • 设置分割线在子View中的位置

      android:showDividers="middle"
      
    • 设置分割线的Padding

      android:dividerPadding="10dp"
      
  • 实现效果:

1655967147943.png

  • 完整布局代码:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="ui.LineraLayoutSuper"
        android:orientation="vertical"
    ​
        android:divider="@drawable/divider_line"
        android:showDividers="middle"
        android:dividerPadding="10dp"
        >
    ​
        <TextView
            android:text="TextView A"
            android:textSize="35sp"
            android:id="@+id/textviewA"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/white"/>
    ​
        <TextView
            android:text="TextView B"
            android:textSize="35sp"
            android:id="@+id/textviewB"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/white"/>
    ​
        <TextView
            android:text="TextView C"
            android:textSize="35sp"
            android:id="@+id/textviewC"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/white"/>
    ​
    </LinearLayout>
    

线性布局的局限:无法处理子View相对摆放

业务需求:

  • 线性布局水平摆放两个元素(TextViewA 与 TextViewB),希望设置A在左边,B在右边

尝试操作一:设置子View的layout_gravity属性(子View相对于父容器的摆放位置)

  • 布局代码:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="ui.LineraLayoutSuper"
        android:orientation="horizontal"
        >
    ​
        <TextView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_gravity="left"
            android:background="#FF7878"
            android:gravity="center"
            android:text="左边" />
    ​
        <TextView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_gravity="right"
            android:background="#FF7428"
            android:gravity="center"
            android:text="右边" />
    ​
    </LinearLayout>
    
  • 运行效果:

1655967750798.png

  • 问题出现原因:

    • 当 android:orientation="vertical" 时, 只有水平方向的设置才起作用,垂直方向的设置不起作用。 即:left,right,center_horizontal 是生效的。 当 android:orientation="horizontal" 时, 只有垂直方向的设置才起作用,水平方向的设置不起作用。 即:top,bottom,center_vertical 是生效的。

补充:将上例父容器orientation设为vertical,出现一个怪怪的效果

  • 测试代码:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        ……
        android:orientation="vertical"
        >
        
        ……
    ​
    </LinearLayout>
    
  • 运行效果:

1655967931536.png

  • 出现原因:为什么会发生这种事情?

    • 这个跟orientation优先级有关
  • 解决手段:此时就应该引入相对布局处理问题

猜你喜欢

转载自juejin.im/post/7112334217882632222
今日推荐