自定义 View 分类
- 继承View重写onDraw方法。实现一些不规则效果。需要自己支持wrap_content,padding也需自己处理。
- 继承ViewGroup派生特殊的Layout。实现自定义布局。需要合适的处理ViewGroup的测量和布局这两个过程,并同时处理子元素的测量和布局过程。
- 继承特定的View(如TextView)。用于扩展。不需要自己支持wrap_content,padding等。
- 继承特定的ViewGroup(如LinearLayout)。用于扩展。不需要处理ViewGroup的测量和布局这两个过程。
继承现有控件
相对而言,这是一种较简单的实现方式。因为大部分核心工作,比如关于控件大小的测量、控件位置的摆放等相关的计算,在系统中都已经实现并封装好,开发人员只要在其基础上进行一些扩展,并按照自己的意图显示相应的 UI 元素。比如以下代码:
public class CustomToolBar extends RelativeLayout {
private ImageView leftImg, rightImg;
private TextView titleTextView;
//1.声明一个接口
public interface ImgClickListener{
public void leftImgClick();
public void rightImgClick();
}
//2.创建一个接口变量
private ImgClickListener imgClickListener;
//3.为接口变量声明一个set方法,
public void setImgClickListener(ImgClickListener imgClickListener) {
this.imgClickListener = imgClickListener;
}
public CustomToolBar(Context context) {
this(context, null);
}
public CustomToolBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomToolBar(final Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
titleTextView = new TextView(context);
leftImg = new ImageView(context);
leftImg.setPadding(12, 12, 12, 12);
rightImg = new ImageView(context);
rightImg.setPadding(12, 12, 12, 12);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomToolBar);
String titleText = ta.getString(R.styleable.CustomToolBar_titleText);
//第二个参数表示默认颜色
int titleTextColor = ta.getColor(R.styleable.CustomToolBar_myTitleTextColor, Color.BLACK);
//已经由sp转为px
float titleTextSize = ta.getDimension(R.styleable.CustomToolBar_titleTextSize, 12);
//读取图片
Drawable leftDrawable = ta.getDrawable(R.styleable.CustomToolBar_leftImageSrc);
Drawable rightDrawable = ta.getDrawable(R.styleable.CustomToolBar_rightImageSrc);
//回收TypedArray
ta.recycle();
leftImg.setImageDrawable(leftDrawable);
rightImg.setImageDrawable(rightDrawable);
titleTextView.setText(titleText);
titleTextView.setTextSize(titleTextSize);
titleTextView.setTextColor(titleTextColor);
//给控件设置LayoutParams时,该控件的父容器是那个,就选那个的LayoutParams
LayoutParams leftParams = new LayoutParams((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, getResources().getDisplayMetrics()),
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, getResources().getDisplayMetrics()));
//表示该控件和父容器的左边对齐
leftParams.addRule(ALIGN_PARENT_LEFT, TRUE);
this.addView(leftImg, leftParams);
LayoutParams titleParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
titleParams.addRule(CENTER_IN_PARENT, TRUE);
addView(titleTextView, titleParams);
LayoutParams rightParams = new LayoutParams((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, getResources().getDisplayMetrics()),
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, getResources().getDisplayMetrics()));
rightParams.addRule(ALIGN_PARENT_RIGHT, TRUE);
addView(rightImg, rightParams);
//4.点击ImageView时调用接口中的方法
leftImg.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (imgClickListener!=null) {
imgClickListener.leftImgClick();
}
}
});
rightImg.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (imgClickListener!=null) {
imgClickListener.rightImgClick();
}
}
});
}
}
复制代码
自定义属性
有时候我们想在 XML 布局文件中使用 CustomToolBar 时,希望能在 XML 文件中直接指定 title 的显示内容、字体颜色,leftImage 和 rightImage 的显示图片等。这就需要使用自定义属性。自定义属性具体步骤分为以下几步:
attrs.xml 中声明自定义属性
在 res 的 values 目录下的 attrs.xml 文件中(没有就自己新建一个),使用 标签自定义属性,如下所示:
复制代码
解释说明:
- 标签代表定义一个自定义属性集合,一般会与自定义控件结合使用;
- 标签则是某一条具体的属性,name 是属性名称,format 代表属性的格式。
在 XML 布局文件中使用自定义属性
需要先添加命名空间 xmlns:app,然后通过命名空间 app 引用自定义属性,并传入相应的图片资源和字符串内容。
xmlns:app="http://schemas.android.com/apk/res-auto"
复制代码
在 CustomToolBar 中获取自定义属性的引用值
public CustomToolBar(Context context, AttributeSet attrs) {
super(context, attrs);
// 主要是通过 Context.obtainStyleAttributes 方法获取到自定义属性的集合,然后从这个集合中取出相应的自定义属性。
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CustomToolBar);
String titleText = ta.getString(R.styleable.CustomToolBar_titleText);
int titleTextColor = ta.getColor(R.styleable.CustomToolBar_myTitleTextColor, Color.BLACK);
// 已经由 sp 转为 px
float titleTextSize = ta.getDimension(R.styleable.CustomToolBar_titleTextSize,12);
// 读取图片
Drawable leftDrawable = ta.getDrawable(R.styleable.CustomToolBar_leftImageSrc);
Drawable rightDrawable = ta.getDrawable(R.styleable.CustomToolBar_rightImageSrc);
}
复制代码
直接继承自 View 或者 ViewGroup
这种方式相比第一种麻烦一些,但是更加灵活,也能实现更加复杂的 UI 界面。一般情况下使用这种实现方式需要解决以下几个问题:
- 自定义控件的大小,也就是宽和高分别设置多少;
- 如果是 ViewGroup,如何合理安排其内部子 View 的摆放位置;
- 如何根据相应的属性将 UI 元素绘制到界面。
以上 3 个问题依次在如下 3 个方法中得到解决:
- onMeasure
- onLayout
- onDraw
因此自定义 View 的重点工作其实就是复写并合理的实现这 3 个方法。注意:并不是每个自定义 View 都需要实现这 3 个方法,大多数情况下只需要实现其中 2 个甚至 1 个方法也能满足需求。
本文在开源项目:https://github.com/Android-Alvin/Android-LearningNotes 中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中...
作者:非也缘也
链接:https://juejin.cn/post/6926148772640587783