Android 自定义 View 分类

自定义 View 分类

  1. 继承View重写onDraw方法。实现一些不规则效果。需要自己支持wrap_content,padding也需自己处理。
  2. 继承ViewGroup派生特殊的Layout。实现自定义布局。需要合适的处理ViewGroup的测量和布局这两个过程,并同时处理子元素的测量和布局过程。
  3. 继承特定的View(如TextView)。用于扩展。不需要自己支持wrap_content,padding等。
  4. 继承特定的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

你可能感兴趣的:(Android 自定义 View 分类)