当前位置:   article > 正文

Android开发基础——自定义控件_android 自定义控件

android 自定义控件

Android中常用控件和布局的继承结构如下图所示:

 从上面可以看出,所有控件都是直接或间接继承自View的,所用的所有布局都是直接或间接继承自ViewGroup的。View是Android中最基本的一种UI组件,其可以在屏幕上绘制一块矩形区域,并能够响应这块区域的各种事件,因此,用户使用的各种控件其实就是在View的基础上又添加了各自特有的功能。而ViewGroup则是一种特殊的View,其可以包含很多子View和子ViewGroup,是一个用于放置控件和布局的容器。

除此之外,也可以创建自定义控件

引入布局

这里创建一个自定义的标题栏。

首先在layout目录下新建一个title.xml布局:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="wrap_content"
  5. android:background="@drawable/title_bg">
  6. <Button
  7. android:id="@+id/titleBack"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:layout_gravity="center"
  11. android:layout_margin="5dp"
  12. android:background="@drawable/back_bg"
  13. android:text="Back"
  14. android:textColor="#fff"/>
  15. <TextView
  16. android:id="@+id/titleText"
  17. android:layout_width="0dp"
  18. android:layout_height="wrap_content"
  19. android:layout_gravity="center"
  20. android:layout_weight="1"
  21. android:gravity="center"
  22. android:text="Title Text"
  23. android:textColor="#fff"
  24. android:textSize="24sp"/>
  25. <Button
  26. android:id="@+id/titleEdit"
  27. android:layout_width="wrap_content"
  28. android:layout_height="wrap_content"
  29. android:layout_gravity="center"
  30. android:layout_margin="5dp"
  31. android:background="@drawable/edit_bg"
  32. android:text="Edit"
  33. android:textColor="#fff"/>
  34. </LinearLayout>

上面的代码中,在LinearLayout中加入了两个Button和一个TextView,左侧的Button用于返回,右侧的Button用于编辑,中间的TextView用于显示标题文本。

android:background属性用于为布局或控件指定一个背景,可以使用颜色或图片来进行填充。android:margin属性可以指定控件在上下左右方向上的间距,也可以使用android:layout_marginLeft或android:layout_marginRight等属性来单独指定控件在某个方向上的间距。

然后修改activity_main.xml中的代码:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent">
  5. <include layout="@layout/title"/>
  6. </LinearLayout>

再隐藏系统自带的标题栏:

  1. package com.example.uicustomviews
  2. import androidx.appcompat.app.AppCompatActivity
  3. import android.os.Bundle
  4. class MainActivity : AppCompatActivity() {
  5. override fun onCreate(savedInstanceState: Bundle?) {
  6. super.onCreate(savedInstanceState)
  7. setContentView(R.layout.activity_main)
  8. supportActionBar?.hide()
  9. }
  10. }

上面使用getSupportActionBar方法获取ActionBar的实例,然后调用其hide方法将标题栏隐藏。程序运行结果为:

 使用这种方法,不管有多少布局需要添加标题栏,只需要一行include语句就可以了。

创建自定义控件

引入布局可以解决重复编写布局代码的问题,但是如果布局中有一些控件要求能够响应事件,还是需要在每个activity中为这些控件单独编写一次事件注册的代码。比如标题栏中的返回按钮,其实不管是在哪一个Acitvity中,这个按钮的功能都是相同的,即销毁当前Activity。而如果每一个Activity都需要重新注册该事件,就会增加很多重复代码,该情况最好使用自定义控件的方式来解决。

新建TitleLayout继承自LinearLayout,使其称为自定义的标题栏控件:

  1. package com.example.uicustomviews
  2. import android.content.Context
  3. import android.util.AttributeSet
  4. import android.view.LayoutInflater
  5. import android.widget.LinearLayout
  6. class TitleLayout(context: Context, attrs:AttributeSet):LinearLayout(context, attrs) {
  7. init {
  8. LayoutInflater.from(context).inflate(R.layout.title, this)
  9. }
  10. }

在TitleLayout的主构造函数中声明了Context和AttributeSet这两个参数,在布局中引入TitleLayout控件时就会调用该构造函数,然后在init结构体中需要对标题栏布局进行动态加载,这就要借助LayoutInflater来实现。通过LayoutInflater的from方法可以构建出一个LayoutInflater对象,然后调用inflate方法就可以动态加载一个布局文件。inflate方法接收两个参数,第一个参数是需要加载的布局文件的id,这里是R.layout.title,第二个参数是给加载好的布局再添加一个父布局,这里指定为TitleLayout,也就是this。

然后在布局文件中添加该自定义控件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent">
  5. <com.example.uicustomviews.TitleLayout
  6. android:layout_width="match_parent"
  7. android:layout_height="wrap_content"/>
  8. </LinearLayout>

添加自定义控件和添加普通控件的方式基本类似,只不过在添加自定义控件的时候,需要指明控件的完整类名,包名不可忽略。

然后为标题栏中的按钮注册点击事件:

  1. package com.example.uicustomviews
  2. import android.app.Activity
  3. import android.content.Context
  4. import android.util.AttributeSet
  5. import android.view.LayoutInflater
  6. import android.widget.LinearLayout
  7. import android.widget.Toast
  8. import kotlinx.android.synthetic.main.title.view.*
  9. class TitleLayout(context: Context, attrs:AttributeSet):LinearLayout(context, attrs) {
  10. init {
  11. LayoutInflater.from(context).inflate(R.layout.title, this)
  12. titleBack.setOnClickListener {
  13. val activity = context as Activity
  14. activity.finish()
  15. }
  16. titleEdit.setOnClickListener {
  17. Toast.makeText(context,"You clicked Edit button", Toast.LENGTH_SHORT).show()
  18. }
  19. }
  20. }

上面的代码其实也好理解,不过需要注意的是TitleLayout中接收的context实际上是Activity的实例,在返回按钮的点击事件中,需要先将之转换为Activity类型,然后调用finish方法销毁当前的Activity。Kotlin中的类型强制转换使用的是关键字as。

程序运行结果为:

 这样也就实现了自定义控件,同时每当在布局中引入TitleLayout时,返回按钮和编辑按钮的点击事件就已经自动实现了,也就省去了重复编写代码的工作。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/110086
推荐阅读
相关标签
  

闽ICP备14008679号