Android中常用控件和布局的继承结构如下图所示:
从上面可以看出,所有控件都是直接或间接继承自View的,所用的所有布局都是直接或间接继承自ViewGroup的。View是Android中最基本的一种UI组件,其可以在屏幕上绘制一块矩形区域,并能够响应这块区域的各种事件,因此,用户使用的各种控件其实就是在View的基础上又添加了各自特有的功能。而ViewGroup则是一种特殊的View,其可以包含很多子View和子ViewGroup,是一个用于放置控件和布局的容器。
除此之外,也可以创建自定义控件。
引入布局
这里创建一个自定义的标题栏。
首先在layout目录下新建一个title.xml布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/title_bg">
<Button
android:id="@+id/titleBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:background="@drawable/back_bg"
android:text="Back"
android:textColor="#fff"/>
<TextView
android:id="@+id/titleText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:text="Title Text"
android:textColor="#fff"
android:textSize="24sp"/>
<Button
android:id="@+id/titleEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:background="@drawable/edit_bg"
android:text="Edit"
android:textColor="#fff"/>
</LinearLayout>
上面的代码中,在LinearLayout中加入了两个Button和一个TextView,左侧的Button用于返回,右侧的Button用于编辑,中间的TextView用于显示标题文本。
android:background属性用于为布局或控件指定一个背景,可以使用颜色或图片来进行填充。android:margin属性可以指定控件在上下左右方向上的间距,也可以使用android:layout_marginLeft或android:layout_marginRight等属性来单独指定控件在某个方向上的间距。
然后修改activity_main.xml中的代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/title"/>
</LinearLayout>
再隐藏系统自带的标题栏:
package com.example.uicustomviews
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()
}
}
上面使用getSupportActionBar方法获取ActionBar的实例,然后调用其hide方法将标题栏隐藏。程序运行结果为:
使用这种方法,不管有多少布局需要添加标题栏,只需要一行include语句就可以了。
创建自定义控件
引入布局可以解决重复编写布局代码的问题,但是如果布局中有一些控件要求能够响应事件,还是需要在每个activity中为这些控件单独编写一次事件注册的代码。比如标题栏中的返回按钮,其实不管是在哪一个Acitvity中,这个按钮的功能都是相同的,即销毁当前Activity。而如果每一个Activity都需要重新注册该事件,就会增加很多重复代码,该情况最好使用自定义控件的方式来解决。
新建TitleLayout继承自LinearLayout,使其称为自定义的标题栏控件:
package com.example.uicustomviews
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
class TitleLayout(context: Context, attrs:AttributeSet):LinearLayout(context, attrs) {
init {
LayoutInflater.from(context).inflate(R.layout.title, this)
}
}
在TitleLayout的主构造函数中声明了Context和AttributeSet这两个参数,在布局中引入TitleLayout控件时就会调用该构造函数,然后在init结构体中需要对标题栏布局进行动态加载,这就要借助LayoutInflater来实现。通过LayoutInflater的from方法可以构建出一个LayoutInflater对象,然后调用inflate方法就可以动态加载一个布局文件。inflate方法接收两个参数,第一个参数是需要加载的布局文件的id,这里是R.layout.title,第二个参数是给加载好的布局再添加一个父布局,这里指定为TitleLayout,也就是this。
然后在布局文件中添加该自定义控件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.uicustomviews.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
添加自定义控件和添加普通控件的方式基本类似,只不过在添加自定义控件的时候,需要指明控件的完整类名,包名不可忽略。
然后为标题栏中的按钮注册点击事件:
package com.example.uicustomviews
import android.app.Activity
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import android.widget.Toast
import kotlinx.android.synthetic.main.title.view.*
class TitleLayout(context: Context, attrs:AttributeSet):LinearLayout(context, attrs) {
init {
LayoutInflater.from(context).inflate(R.layout.title, this)
titleBack.setOnClickListener {
val activity = context as Activity
activity.finish()
}
titleEdit.setOnClickListener {
Toast.makeText(context,"You clicked Edit button", Toast.LENGTH_SHORT).show()
}
}
}
上面的代码其实也好理解,不过需要注意的是TitleLayout中接收的context实际上是Activity的实例,在返回按钮的点击事件中,需要先将之转换为Activity类型,然后调用finish方法销毁当前的Activity。Kotlin中的类型强制转换使用的是关键字as。
程序运行结果为:
文章来源:https://www.toymoban.com/news/detail-409036.html
这样也就实现了自定义控件,同时每当在布局中引入TitleLayout时,返回按钮和编辑按钮的点击事件就已经自动实现了,也就省去了重复编写代码的工作。文章来源地址https://www.toymoban.com/news/detail-409036.html
到了这里,关于Android开发基础——自定义控件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!