Android 自定义 View 分类

作者: Kepler_II | 来源:发表于2021-02-07 11:55 被阅读0次

    自定义 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 文件中(没有就自己新建一个),使用 标签自定义属性,如下所示:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="CustomToolBar">
            <attr name="titleText" format="string|reference"/>
            <attr name="myTitleTextColor" format="color|reference"/>
            <attr name="titleTextSize" format="dimension|reference"/>
            <attr name="leftImageSrc" format="reference"/>
            <attr name="rightImageSrc" format="reference"/>
        </declare-styleable>
    </resources>
    复制代码
    

    解释说明:

    • 标签代表定义一个自定义属性集合,一般会与自定义控件结合使用;
    • 标签则是某一条具体的属性,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 分类

        本文链接:https://www.haomeiwen.com/subject/nqkztltx.html