anroid 自定义控件

本文介绍了在Android中创建自定义控件的方法,特别是如何自定义一个标题栏。首先通过引入布局的方式实现标题栏,然后通过创建TitleLayout控件并重写其构造函数,利用LayoutInflater加载布局文件。此外,还展示了如何为标题栏的按钮添加点击事件监听,减少重复代码,提高代码维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

anroid 自定义控件

@author lisiwen

@createTime 2022/4/11

示例代码地址:https://github.com/NET-lisiwen/UICustomViews/tree/master


​ 之前我们学习了Android中一些常用控件和基本布局的用法,不过当时我们并没有关注这些控件的布局的继承结构,现在来看一下

在这里插入图片描述

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

​ 这个时候我们就可以思考一下,当系统自带的控件并不能满足我们的需求时,可不可以利用上面的继承结构来创建个自定义的控件呢?答案时肯定的,下面我们就来尝试一下创建自定义控件的两种简单方法。

1.引入布局

​ 如果说使用过iphone,应该知道,iphone应用的界面顶部都有一个标题栏,标题栏上会有一到两个按钮用于其他操作因为iphone没有专门的返回键。现在在很多Android程序喜欢模仿iphone风格,会在界面的顶部也放置一个标题栏。虽然说android给每个activity提供了标题栏的功能,我们这里先决定不使用他,而是创建一个自定义个标题栏。

​ 经过前两节的学习之后,创建一个自定义的标题栏相信已经不是什么难事了,使用LinearLayout布局加入两个Button和一个TextView就好了。可是这样会有一个问题,一般我们一个应用程序可能又很多activity,如果都需要这样的标题栏,那么就是说每个activity中都要写一遍相同的代码,不但会导致大量的代码重复,并且也会比较难以维护。这时我们就需要引入布局的方式来解决这个问题,在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="@color/purple_200">

    <Button
        android:id="@+id/backbutton"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:text="back"
        android:textColor="@color/white"
        android:textSize="15sp" />

    <TextView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center"
        android:text="UICustomViews"
        android:textColor="@color/black"
        android:textSize="15sp" />

    <Button
        android:id="@+id/savebutton"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:text="save"
        android:textColor="@color/white"
        android:textSize="15sp" />
</LinearLayout>

​ 可以看到我们在LinearLayout中分别加入了两个Button和一个TextView,左边的Button用于返回,右边的Button可用于保存,中间的TextView可以显示一段标题文本。上面代码中属性大多都是见过的,这个用的一个全新的属性就是android:background,这个就是设置当前标题栏布局的背景色,当然也可以是一张图片,我这里图方便就使用的颜色。

​ 现在标题栏布局已经编写好了,剩下的就是如何在程序中使用这个标题栏了,修改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="wrap_content"
    android:orientation="vertical">
    <include layout="@layout/title"/>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="this is UiCustomViews"/>
</LinearLayout>

​ 没错这里使用一个include语句引入刚才的标题栏布局就可以了。然后下边加入一个TextView来显示内容

​ 关键的一步,还需要再MainActivity中将系统自带的标题栏隐藏掉,代码如下所示:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (getSupportActionBar() != null) {
            getSupportActionBar().hide();
        }
    }
}

​ 这里我们调用了getSupportActionBar()方法来获得ActionBar的实例,然后再调用他的hide()方法将标题栏隐藏起来。运行一下程序 结果如下所示

在这里插入图片描述

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

2.创建自定义控件

	引入布局的技巧的确解决了重复编写布局代码的问题,但是如果布局中有一些控件要求能够响应时间,我们还需要在每个Activity中为这些控件单独编写一次时间注册的代码。比如标题栏中的返回按键,其实不管是哪一个Anticity中这个按键的功能都是相同的,即销毁当前Activity,而如果在每个Activity中都需要重新注册一遍返回按钮的点击事件,无疑会增加很多重复代码,这种情况最好是使用自定义控件的方式来解决。

​ 新建TitleLayout继承自LinearLayout,让他称为我们自定义标题栏的控件,代码如下

public class TitleLayout extends LinearLayout {

    public TitleLayout(Context context) {
        super(context);
        init(context);
    }

    public TitleLayout(Context context, AttributeSet attrs) {
        this(context);
    }

    private void init(Context context) {
        LayoutInflater.from(context).inflate(R.layout.title, this);
    }
}

​ 我们在TitleLayout的构造参数中调用init初始化方法,在其中对标题栏的布局进行加载,这时候就要借助LayoutInflater来实现了。通过LayoutInflater的from()方法可以构建出一个LayoutInflater对象,然后调用inflate方法就可以动态加载一个布局文件。inflate()方法接受两个参数,第一个参数是要加载的布局文件的id,这里我们传入R.layout.title,第二个参数就是给加载好的布局再添加一个父布局,这里我们需要指定为TitleLayout,于是直接传入this。

​ 现在自定义控件已经创建好了,接下来我们需要在布局文件中添加这个自定义控件,修改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="wrap_content"
    android:orientation="vertical">
    <com.example.uicustomviews.TitleLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="this is UiCustomViews"/>
</LinearLayout>

​ 添加自定义控件和添加普通控件的方式是基本一直的,只不过就是添加自定义控件的时候,要指定完整的包名,包名在这里是不可以省略的。

​ 重新运行程序,你会发现此时的效果和使用引入布局的方式的效果是一样的。

​ 下面我们尝试给标题栏的button添加点击的监听事件,修改TitleLayout中的代码如下所示

public class TitleLayout extends LinearLayout implements View.OnClickListener {

    public TitleLayout(Context context) {
        super(context);
        init(context);
    }

    public TitleLayout(Context context, AttributeSet attrs) {
        this(context);
    }

    private void init(Context context) {
        LayoutInflater.from(context).inflate(R.layout.title, this);
        findViewById(R.id.backbutton).setOnClickListener(this);
        findViewById(R.id.savebutton).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.backbutton:
                Toast.makeText(getContext(), "click back button", Toast.LENGTH_SHORT).show();
                if (getContext() instanceof Activity) {
                    ((Activity) getContext()).finish();
                }
                break;
            case R.id.savebutton:
                Toast.makeText(getContext(), "click save button", Toast.LENGTH_SHORT).show();
                break;
            default:
                Toast.makeText(getContext(), "click default button", Toast.LENGTH_SHORT).show();
                break;
        }

    }
}

​ 这里我们分别给返回和保存按钮注册了点击时间,当点击返回按键的时候,会进行一次点击提示,然后销毁将context转为Activity并且调用finish()销毁当前activity,点击保存按钮时,弹出一段文本。

​ 重新运行程序,点击一下保存按钮,效果如图所示

在这里插入图片描述

​ 这样的话,每当我们在一个布局中阴图TitleLayout时,返回按键和编辑按钮的点击事件就已经自动实现好了,就省去了很多重复代码的工作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值