前言
转载请声明,转自【https://www.cnblogs.com/andy-songwei/p/10979161.html】,谢谢!
尽管Android系统提供了不少控件,但是有很多酷炫效果仍然是系统原生控件无法实现的。好在Android允许自定义控件,来弥补原生控件的不足。但是在很多初学者看来,自定义View似乎很难掌握。其中有很大一部分原因是我们平时看到的自定义View使用中,有多种形式,有的寥寥数笔,有的逻辑很复杂,有的直接继承View或ViewGroup,有的却直接继承系统的原生控件,有的可以直接使用系统定义的属性,而有的却自定义了自己的属性......所以不明白使用规则的开发者,很容易被这只“纸老虎”吓到。
实际上实现自定义View的方式,从整体上看,只分为三种:组合控件,继承控件,自绘控件。然后就是根据需要来添加自定义的属性,就这么简单。本文将会针对这4个方面进行详细的讲解。主要内容如下:
一、组合控件
组合控件,顾名思义,就是将系统原有的控件进行组合,构成一个新的控件。这种方式下,不需要开发者自己去绘制图上显示的内容,也不需要开发者重写onMeasure,onLayout,onDraw方法来实现测量、布局以及draw流程。所以,在实现自定义view的三种方式中,这一种相对比较简单。
实际开发中,标题栏就是一个比较常见的例子。因为在一个app的各个界面中,标题栏基本上是大同小异,复用率很高。所以经常会将标题栏单独做成一个自定义view,在不同的界面直接引入即可,而不用每次都把标题栏布局一遍。本节就自定义一个标题栏,包含标题和返回按钮两个控件,来介绍这种组合控件的实现方式。
1、定义标题栏布局文件
定义标题栏的布局文件custom_title_view.xml,将返回按钮和标题文本进行组合。这一步用于确定标题栏的样子,代码如下所示:
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="wrap_content" 5 android:background="@android:color/holo_orange_light"> 6 <Button 7 android:id="@+id/btn_left" 8 android:layout_width="wrap_content" 9 android:layout_height="wrap_content" 10 android:layout_centerVertical="true" 11 android:layout_marginLeft="5dp" 12 android:text="Back" 13 android:textColor="@android:color/white" /> 14 15 <TextView 16 android:id="@+id/title_tv" 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:layout_centerInParent="true" 20 android:text="Title" 21 android:textColor="@android:color/white" 22 android:textSize="20sp" /> 23 </RelativeLayout>
这个布局很简单,就不多说了。
2、根据给定布局实现自定义View
1 public class CustomTitleView extends FrameLayout implements View.OnClickListener { 2 private View.OnClickListener mLeftOnClickListener; 3 private Button mBackBtn; 4 private TextView mTittleView; 5 6 public CustomTitleView(@NonNull Context context, @Nullable AttributeSet attrs) { 7 super(context, attrs); 8 LayoutInflater.from(context).inflate(R.layout.custom_title_view, this); 9 mBackBtn = findViewById(R.id.btn_left); 10 mBackBtn.setOnClickListener(this); 11 mTittleView = findViewById(R.id.title_tv); 12 } 13 14 @Override 15 public void onClick(View v) { 16 switch (v.getId()) { 17 case R.id.btn_left: 18 if (mLeftOnClickListener != null) { 19 mLeftOnClickListener.onClick(v); 20 } 21 break; 22 } 23 } 24 25 public void setLeftOnClickListener(View.OnClickListener leftOnClickListener) { 26 mLeftOnClickListener = leftOnClickListener; 27 } 28 29 public void setTittle(String title){ 30 mTittleView.setText(title); 31 } 32 }
为了编译理解和记忆,这里对该部分做一点说明:
(1)代码中对外提供了两个接口,一是动态设置标题,二是使用者可以自定义返回按钮的点击事件。
(2)CustomTitleView的构造函数,要选择两个参数的,选择其它参数的构造函数会报错。这一点是笔者开发机测试的结果,暂时不清楚是不是所有手机上都是这样。
(3)这里是继承的FrameLayout,但是继承LinearLayout,RelativeLayout等系统布局控件都可以。之所以要继承这些系统现成的ViewGroup,是因为这样可以不用再重写onMeasure,onLayout等,这样省事很多。由于这里是一个布局控件,要用LayoutInflater来填充,所以需要继承ViewGroup,如果继承View的直接子类,编译会不通过。所以,CustomTitleView自己就是一个容器,完全可以当成容器使用,此时CustomTitleView自身的内容会和其作为父布局添加的子控件,效果会叠加,具体的叠加效果是根据继承的容器特性决定的。
3、在Activity的布局文件中添加CustomTitleView
在Activity的布局文件activity_custom_view_compose_demo.xml中,像使用系统控件一样使用CustomTitleView即可。前说了,CustomTitleView自己就是继承的现成的系统布局,所以它们拥有的属性特性,CustomTitleView一样拥有。
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent"> 5 <com.example.demos.customviewdemo.CustomTitleView 6 android:id="@+id/customview_title" 7 android:layout_width="match_parent" 8 android:layout_heig