Android 常用布局容器

  • Android 的 UI 可以分为两类,一类叫做 ViewGroup 容器,一类叫做 View 视图
  • ViewGroup 容器:(LinearLayout,RelativeLayout,FrameLayout)都是常用常见的容器.
  • View 视图:(TextView,Button,ImageView)都是常用常见的视图.

1.基础布局容器

  • LinearLayout线性布局:横着或竖着按顺序排列

  • RelativeLayout相对布局:起始坐标时屏幕左上角,以同级或上级为参考系定位位置(以屏幕的左上角为常考点来摆放它们的位置)

  • FrameLayout帧布局:像千层饼一样,一层压着一层(同样以屏幕的左上角为常考点来确定它们的位置)

  • ConstraintLayout 约束布局:google 于 2016 年新发布的一种布局方式,它不在 android 的基础 api 包里,需要额外引入

  • AbsoluteLayout 绝对布局(以屏幕左上角为参考系,定位自己的位置,从 android 2.2 版本后废弃)

  • GridLayout 网格布局(可以指定行数列数,子控件自动根据行列数进行分配位置,于 android 4.0 后新增进 api 中)

  • TableLayout 表格布局(类似于网格布局,以一个 TableRow 标签定义为一行或一列)

2.线性布局 LinearLayout

属性可选值说明
orientation1.vertical:垂直排列 2.horizontal:水平排列(从左到右)也就是这个线性布局到底是水平方向逐个排列还是垂直方向逐个排列
layout_width layout_height1.match_parent:填充父容器的剩余空间 2.wrap_content:根据子视图宽高自适应自己的宽高 3.自定义大小 50dplayout_width 和 layout_height 是 android 中控件的必要属性,规定了控件的宽度和高度,这个两个属性的值可以是指定的值,也可以根据内容自适应,还可以填充整个剩余空间
background#ff0000 红色填充背景色
gravity1.center:所有子视图相对于父容器居中显示 2.horizontal_center:所有子容器的横向方向上相对父容器居中显示 3.vertical_center:所有子视图的纵向方向上相对父容器居中显示决定子控件相对该父容器的位置(对齐方式的表示)
layout_gravity1.center:该容器相对于它的父容器居中显示 2.horizontal_center:该容器横向方向上相对它的父容器居中显示 3.vertical_center:该容器纵向方向上相对它的父容器居中显示决定该容器相对它的父容器的位置
weight按比例分配父容器剩余的宽度或高度

提示:

  • button 高版本改变背景色要用 android:backgroundTint 属性

  • android:layout_gravity 如果对齐方式和 android:orientation 方向一致就会失效

  • 在父类中使用 子类相较与父类的布局 android:gravity 子控件使用 android:layout_gravity

  • orientation="vertical"时 layout_weight 等比分配高度使用 orientation="horizontal"时 layout_weight 等比分配宽度

  • layout_weight 则 layout_width 失效当 layout_width=“0dp” layout_weight=数字越大宽度越长

3. 相对布局 RelativeLayout

  • 相对布局在摆放子视图位置时,按照指定的参考系来摆放子视图的位置,默认以屏幕左上角(0,0)位置作为参考系摆放位置

  • 相对于父元素 7 个常用属性

属性可选值说明
layout_alignParentToptrue/false是否相对于父容器的顶部
layout_alignParentBottomtrue/false是否相对于父容器的底部
layout_alignParentLefttrue/false是否相对于父容器的左边
layout_alignParentRighttrue/false是否相对于父容器的右边
layout_centerHorizontaltrue/false是否相对于父容器的水平方向居中
layout_centerVerticaltrue/false是否相对于父容器的垂直方向居中
layout_centerInParenttrue/false是否相对于父容器的水平和垂直方向居中
  • 相对于兄弟元素 4 个常用属性
属性可选值说明
layout_above@id/控件 id是否相对于指定控件的上方
layout_below@id/控件 id是否相对于指定控件的下方
layout_toLeftOf@id/控件 id是否相对于指定控件的左边
layout_toRightOf@id/控件 id是否相对于指定控件的右边
  • 相对于兄弟元素的对齐方式
属性可选值说明
layout_alignTop@id/控件 id是否相对于指定控件的顶部对齐
layout_alignBottom@id/控件 id是否相对于指定控件的底部对齐
layout_alignLeft@id/控件 id是否相对于指定控件的左边对齐
layout_alignRight@id/控件 id是否相对于指定控件的右边对齐

4. 帧布局 FrameLayout

  • 组件的默认位置都是左上角,组件之间可以重叠。像千层饼一样,一层压着一层 可以设置上下左右的对齐、水平垂直居中、设置方式与线性布局相似。

  • 常用属性

属性可选值说明
layout_gravitycenter/center_vertical/center_horizontal设置组件在父容器中的位置
layout_marginLeft具体的数值 100dp左侧外间距
layout_marginTop具体的数值 100dp顶部外间距
layout_marginRight具体的数值 100dp右侧外间距
layout_marginBottom具体的数值 100dp底部外间距

MaterialButton

  • MaterialButton 是 Google 于 SDK28 推出的新控件,当遇到按钮需要圆角、或者描边等,就不必使用 xml 文件或者 Github 上找第三方库实现

1.1 依赖引入

  • 添加依赖 我的项目默认添加了 material 1.4.0
  • Project 文件模式下 app—> bulid.gradle
implementation 'com.google.android.material:material:1.3.0'
  • app 的 theme 主题修改
# app—>src---->main---->AndroidManifest.xml

android:theme="@style/Theme.项目名"
<--!点击进入这个theme文件-->
<--!进入一个themes.xml文件-->
<style name="Theme.项目名" parent="xxx">
# 改为
<style name="Theme.项目名" parent="Theme.MaterialComponents.Light.NoActionBar">

1.2 继承关系

java.lang.Object
 ↳android.view.View
  ↳android.widget.TextView
   ↳android.widget.Button
    ↳androidx.appcompat.widget.AppCompatButton
     ↳com.google.android.material.button.MaterialButton

1.3 关键属性

属性描述说明
app:cornerRadius圆角大小设置按钮的圆角大小
app:strokeColor描边颜色设置按钮的描边颜色
app:strokeWidth描边宽度设置按钮的描边宽度
app:icon图标 icon设置按钮的图标
app:iconGravity图标位置设置按钮的图标位置 start,end.textStart,textEnd
app:backgroundTint背景色设置按钮的背景色
app:backgroundTintMode背景模式设置按钮的背景模式 add,multiply,screen,src_atop,src_in,src_over
app:iconTint图标颜色设置按钮的图标颜色
app:iconPadding图标间距设置按钮的图标间距
app:iconSize图标大小设置按钮的图标大小
app:rippleColor水波纹色设置按钮的水波纹颜色
app.iconTintMode图标模式设置按钮的图标模式
  • 根节点添加 app 命名空间

    xmlns:app="http://schemas.android.com/apk/res-auto"
    

1.4 注意事项

  • 去除阴影: MD 控件默认有阴影效果,但是有时候我们并不想要按钮有阴影,那么这时候可以指定 style 为 style="@style/Widget.MaterialComponents.Button.UnelevatedButton" 这样就能去掉阴影,让视图看起来扁平化

  • 闪退: 修改 APP 主题

android:theme="@style/Theme.MaterialComponents.Light.NoActionBar"

MaterialButtonToggleGroup

1.1 继承关系

java.lang.Object
   ↳android.view.View
        ↳android.view.ViewGroup
             ↳android.widget.LinearLayout
                  ↳com.google.android.material.button.MaterialButtonToggleGroup

  • 只有第一个子元素的最左边角和最后一个子元素的最右边角才能保留它们的形状外观圆角大小 app:cornerRadius 修改圆角

1.2 公开属性

属性描述说明
app:checkedButton默认选中按钮 ID
app:singleSelection是否单项选择true(单选)/false(多选)
app:selectionRequired是否必选true(必选)/false(非必选)

1.3 tab 切换监听

  • MaterialButtonToggleGroup 继承 LinearLayout 可以使用 weight
  • 在 comps_material_button.xml 写布局 在 MainActivity.kt 写监听

TextView 文本控件

1. 常用属性

属性属性值示例说明
android:id@+id/tv设置一个组件 id,通过 findViewById()的方法获取到该对象,然后进行相关设置
android:text@string/xxx设置文本内容
android:textSize20sp设置文本大小
android:textColor#ff0000设置文本颜色
android:gravitycenter设置文本对齐方式
android:background#ff0000设置文本背景色
android:padding10dp设置文本内边距
android:paddingLeft10dp设置文本左内边距
android:paddingTop10dp设置文本上内边距
android:paddingRight10dp设置文本右内边距
android:paddingBottom10dp设置文本下内边距
android:drawableLeft@mipmap/ic_launcher设置文本左边图标
android:drawableTop@mipmap/ic_launcher设置文本上边图标
android:drawableRight@mipmap/ic_launcher设置文本右边图标
android:drawableBottom@mipmap/ic_launcher设置文本下边图标
android:drawablePadding10dp设置文本图标与文本之间的间距
android:drawableTint#ffffff图片着色数
android:ellipsizeend设置文本超出显示范围时的显示方式
android:maxLines1设置文本最大显示行数
android:inputTypetext设置文本输入类型
android:hint请输入用户名设置文本提示内容
android:passwordtrue设置文本是否以密码形式显示
android:scrollHorizontallytrue设置文本是否水平滚动
android:scrollbarshorizontal设置文本滚动条显示方式
android:linksClickabletrue设置文本是否可点击
android:autoLinkweb设置文本自动识别链接
android:lineSpacingExtra10dp设置文本行间距
android:lineSpacingMultiplier1.5设置文本行间距倍数
android:maxLength10设置文本最大长度
android:singleLinetrue设置文本是否单行显示
android:shadowColor#ff0000设置文本阴影颜色
android:shadowDx10设置文本阴影水平偏移量
android:shadowDy10设置文本阴影垂直偏移量
android:shadowRadius10设置文本阴影半径
android:textStylebold设置文本字体样式

ImageView 图片控件

1.常见属性

属性属性值示例说明
android:src@mipmap/ic_launcher设置图片资源
android:alpha0.5[0.0~1.0]设置透明度
android:backgroun@drawable/background给 ImageView 设置背景色、背景图片
android:scaleTypecenter设置图片缩放类型
  • 注意: 同时设置 src 和 background。background 在下,src 在上

2.常见缩放类型

属性说明
fitXY把原图按照指定的大小在 View 中显示,拉伸显示图片,不保持原比例,填满 ImageView
centerCrop常用,等比放大居中显示以填满整个 ImageView 为目的,将原图的中心对准 ImageView 的中心,等比例放大原图,直到填满 ImageView 为止(指的是 ImageView 的宽和高都要填满),原图超过 ImageView 的部分作裁剪处理。
centerInside以原图完全显示为目的,将图片的内容完整居中显示,通过按比例缩小原图的长(宽)等于或小于 ImageView 的长(宽)。如果原图的长宽本身就小于 ImageView 的长宽,则原图不作任何处理,居中显示在 ImageView
fitCenter把原图按比例扩大或缩小到 ImageView 的 ImageView 的高度,居中显示
matrix不改变原图的大小,从 ImageView 的左上角开始绘制原图,原图超过 ImageView 的部分作裁剪处理。
center保持原图的大小,显示在 ImageView 的中心。当原图的长(宽)大于 ImageView 的长(宽),超过部分裁剪处理。
fitStart把原图按比例扩大(缩小)到 ImageView 的高度,显示在 ImageView 的上部分位置
fitEnd把原图按比例扩大(缩小)到 ImageView 的高度,显示在 ImageView 的下部分位置

效果图

效果图

RecyclerView 高级 UI 控件

 RecyclerView 高级 UI 控件

  • 四层回收、复用机制可以让页面在滑动的时候非常顺滑

1. 列表布局 LinearLayoutManager

1.1 纵向列表

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // 文本 布局方向 是否反转
    FragmentHomeBinding.bind(view).recyclerView.layoutManager = LinearLayoutManager(context , LinearLayoutManager.VERTICAL , false)
    FragmentHomeBinding.bind(view).recyclerView.adapter = MyAdapter()
}

1.2 横向列表

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // 文本 布局方向 是否反转
    FragmentHomeBinding.bind(view).recyclerView.layoutManager = LinearLayoutManager(context , LinearLayoutManager.HORIZONTAL , false)
    FragmentHomeBinding.bind(view).recyclerView.adapter = MyAdapter()
}
  • 共同部分

    • step1: 编写列表 item 的布局样式 item_view_linear_vertical.xml

    • step2: 完善 fragment_home.xml

      • 确保 app–>build.gradle 中 dependencies 有引用
    • step3: 完善 MainActivity.kt

      • 确保 MainActivity.kt 中有引用
      • 关联 fragment_home.xml
      • recycler_view.layoutManager
      • recycler_view.adapter

    class MyViewHolder(val view: View):RecyclerView.ViewHolder(view){
        val binding = ItemViewLinearVerticalBinding.bind(view)
    }

    //内部类可以访问外部类的对象 为了拿到context
    inner class  MyAdapter:RecyclerView.Adapter<MyViewHolder>(){
    //创建对应的ViewHolder对象
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        //资源文件id ViewGroup attachToRoot
        val itemView = LayoutInflater.from(context)
            .inflate(R.layout.item_view_linear_vertical, parent, false)
        return MyViewHolder(itemView)
    }

    //完成数据的绑定
    @SuppressLint("SetTextI18n")
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        //载入图片的三种方式
        /*holder.itemView.item_image.setImageResource(R.drawable.android_icon)
        holder.itemView.item_image.setImageDrawable(ContextCompat.getDrawable(context!!,R.drawable.android_icon))
        holder.itemView.item_image.setImageBitmap(BitmapFactory.decodeResource(context!!.resources , R.drawable.android_icon))*/
        with(holder){
            binding.itemImage.setImageResource(R.drawable.android_icon)
            binding.itemTitle.text = "这是第 ${position+1} 个标题"
            binding.itemMessage.text = "这是第 ${position+1} 个内容,这是第 ${position} 个内容,这是第 ${position} 个内容,这是第 ${position} 个内容"
        }
    }

    //告诉列表有多少数据
    override fun getItemCount(): Int {
        return 20
    }
}

提示:

2. 网格布局 GridLayoutManager

//HomeFragment被解析为view对象时会回调这个方法
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // 文本 几列
    FragmentDashboardBinding.bind(view).recyclerView.layoutManager =
        GridLayoutManager(context , 2)
    FragmentDashboardBinding.bind(view).recyclerView.adapter = MyAdapter()
}

3.瀑布流布局 StaggeredGridLayoutManager

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 几列 方向
        FragmentNotificationsBinding.bind(view).recyclerView.layoutManager =
            StaggeredGridLayoutManager(2 , StaggeredGridLayoutManager.VERTICAL)
        FragmentNotificationsBinding.bind(view).recyclerView.adapter = MyAdapter()
    }

4.view-binding

  • 可以直接使用布局中的控件 id 来操作 view 控件, 不用再 findViewById。大大提高工作效率,减少模板代码量
  • 需要在根目录下的 build.gradle 添加 kotlin-android-extensions 插件

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-android-extensions'
}

# app/build.gradle 中开启
android {
    ...
    buildFeatures {
        viewBinding true
    }
}

参考资料