【5年Android从零复盘系列之六】Android自定义View(1):基础

1.基础一:坐标计算

1.1 Android窗口坐标系计算以屏幕左上角为原点,

向右为X轴正向,向下为Y轴正向

【5年Android从零复盘系列之六】Android自定义View(1):基础_第1张图片

1.2 View坐标系

【注意获取的坐标是像素值,不是dp值】
【注意获取的坐标是像素值,不是dp值】
【注意获取的坐标是像素值,不是dp值】

//获取View内部相对的坐标值(距离)
getX()getY()
//获取View相对父View的相对坐标值(距离)
getLeft()getTop()getRight()getBottom()
//获取的是屏幕中的实际坐标值(距离)
getRawX()getRawY()

图中activity指全屏窗口,严格的讲应该是屏幕

【5年Android从零复盘系列之六】Android自定义View(1):基础_第2张图片

1.3 实际开发使用场景

1.获取View的宽高【应在View绘制完成后调用

width = getRight() - getLeft();
height = getBottom() - getTop();

2.获取View在父view中的左上角坐标【应在View绘制完成后调用

Point point = new Point();
point.set(ivState.getLeft() ,ivState.getTop());

3.获取View在父view中心点坐标【应在View绘制完成后调用

Point point = new Point();
point.set(ivState.getRight() - ivState.getLeft() ,ivState.getBottom() - ivState.getTop());

2. 自定义属性

2.1 构造函数&初始化属性

public class MDButton extends Button {
     
    //java动态创建view时调用
    public MDButton(Context context) {
     
        super(context);
        initInnerView(context);
    }
    //xml布局初始化时调用
    public MDButton(Context context, AttributeSet attrs) {
     
        super(context, attrs);
//        initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用
        initAttrs(context, attrs);
    }
    //有默认style时,在MDButton(Context context, AttributeSet attrs)中调用MDButton(context,attrs,defStyleAttr);
    public MDButton(Context context, AttributeSet attrs, int defStyleAttr) {
     
        super(context, attrs, defStyleAttr);
//        initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用
        initAttrs(context, attrs);
    }
    //只有在API版本>21时才会用到
    //有默认style时,在MDButton(Context context, AttributeSet attrs)中调用MDButton(context,attrs,defStyleAttr);
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MDButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
     
        super(context, attrs, defStyleAttr, defStyleRes);
//        initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用
        initAttrs(context, attrs);
    }
    //组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用
    private void initInnerView(Context context) {
     
        //...
    }
    private void initAttrs(Context context, AttributeSet attrs) {
     
        //...
    }
}

2.2 自定义属性

1.在module中的/res/values/attrs.xml编写属性&类型;


<resources>
    <declare-styleable name="MDButton">
        
        <attr name="mdb_bg" format="color|reference" />
        <attr name="mdb_txt_color" format="color|reference" />
        
        <attr name="mdb_txt" format="string" />
        
        <attr name="mdb_auto_anim" format="boolean" />
        
        <attr name="mdb_anim_pivotX" format="fraction" />
        
        <attr name="mdb_auto_anim_delay" format="integer" />
        
        <attr name="mdb_auto_anim_alpha" format="float" />
        
        <attr name="mdb_min_width" format="dimension" />
        
        <attr name="mdb_size">
            <enum name="small" value="0" />
            <enum name="normal" value="1" />
            <enum name="big" value="2" />
        attr>
        
        <attr name="mdb_radius_corner">
            <flag name="empty" value="0x00" />
            <flag name="top" value="0x01" />
            <flag name="bottom" value="0x02" />
            <flag name="left" value="0x04" />
            <flag name="right" value="0x08" />
        attr>
    declare-styleable>
resources>

2.自定义View类中获取属性值,并使用

public class MDButton extends Button {
     
    //组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用
    private void initInnerView(Context context) {
     
        //...
    }
    private void initAttrs(Context context, AttributeSet attrs) {
     
        //1.获取属性数组
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MDButton);
       
        //2.获取属性值
        Drawable bgDrawable = typedArray.getDrawable(R.styleable.MDButton_mdb_bg);
        int txtColor = typedArray.getInteger(R.styleable.MDButton_mdb_txt_color,Color.parseColor("#808080"));
        String txt = typedArray.getString(R.styleable.MDButton_mdb_txt);
        boolean isAutoAnim = typedArray.getBoolean(R.styleable.MDButton_mdb_auto_anim, false);
        float fraction = typedArray.getFraction(R.styleable.MDButton_mdb_anim_pivotX, 1, 1, 1.0f);
        float alpha = typedArray.getFloat(R.styleable.MDButton_mdb_auto_anim_alpha , 1.0f);
        float minWidth = typedArray.getDimension(R.styleable.MDButton_mdb_min_width, 32.0f);
        int sizeType = typedArray.getInt(R.styleable.MDButton_mdb_size, 1);//0=small 1=normal 2=big
        int radiusCorner = typedArray.getInt(R.styleable.MDButton_mdb_radius_corner ,0);
        int delay = typedArray.getInt(R.styleable.MDButton_mdb_auto_anim_delay ,0);
        Log.e("bgDrawable",""+bgDrawable);
        Log.e("txtColor",""+txtColor);
        Log.e("txt",""+txt);
        Log.e("isAutoAnim",""+isAutoAnim);
        Log.e("fraction",""+fraction);
        Log.e("alpha",""+alpha);
        Log.e("minWidth",""+minWidth);
        Log.e("sizeType",""+sizeType);
        Log.e("radiusCorner",""+radiusCorner);
        Log.e("delay",""+delay);
        Log.e("==============","=========================================");
        
        //3.属性值 设置到 对应属性
        setText(txt);
        //tv.setDelay(delay);
        //...
        
        //4.释放
        typedArray.recycle();
    }
    //java动态创建view时调用
    public MDButton(Context context) {
     
        super(context);
        initInnerView(context);
    }
    //xml布局初始化时调用
    public MDButton(Context context, AttributeSet attrs) {
     
        super(context, attrs);
//        initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用
        initAttrs(context, attrs);
    }
    //有默认style时,在MDButton(Context context, AttributeSet attrs)中调用MDButton(context,attrs,defStyleAttr);
    public MDButton(Context context, AttributeSet attrs, int defStyleAttr) {
     
        super(context, attrs, defStyleAttr);
//        initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用
        initAttrs(context, attrs);
    }
    //只有在API版本>21时才会用到
    //有默认style时,在MDButton(Context context, AttributeSet attrs)中调用
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MDButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
     
        super(context, attrs, defStyleAttr, defStyleRes);
//        initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用
        initAttrs(context, attrs);
    }
}

3.在布局文件.xml中使用控件,【注意变量组设置的数据&单位】

 <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        android:orientation="vertical"
        >
        <com.cupster.base_super_resource.MDButton
            app:mdb_anim_pivotX="80%"
            app:mdb_auto_anim="true"
            app:mdb_auto_anim_alpha="1.0"
            app:mdb_auto_anim_delay="100"
            app:mdb_bg="@drawable/shape_btn_gray_radius5"
            app:mdb_min_width="60dp"
            app:mdb_radius_corner="right"
            app:mdb_size="big"
            app:mdb_txt="btn1"
            app:mdb_txt_color="#ff00ff"

            android:layout_width="120dp"
            android:layout_height="60dp"
            />
        <com.cupster.base_super_resource.MDButton
            app:mdb_anim_pivotX="70%"
            app:mdb_auto_anim="false"
            app:mdb_auto_anim_alpha="0.4"
            app:mdb_auto_anim_delay="100"
            app:mdb_bg="@drawable/shape_btn_gray_radius5"
            app:mdb_min_width="60px"
            app:mdb_radius_corner="bottom|left|top|right"
            app:mdb_size="small"
            app:mdb_txt="btn1"
            app:mdb_txt_color="#ff00ff"

            android:layout_width="120dp"
            android:layout_height="60dp"
            />
        <com.cupster.base_super_resource.MDButton
            app:mdb_anim_pivotX="100%"
            app:mdb_auto_anim_alpha="0.9"
            app:mdb_auto_anim_delay="100"
            app:mdb_bg="@drawable/shape_btn_gray_radius5"
            app:mdb_min_width="90dp"
            app:mdb_radius_corner="empty"
            app:mdb_size="normal"
            app:mdb_txt="btn1"
            app:mdb_txt_color="#ff00ff"

            android:layout_width="120dp"
            android:layout_height="60dp"
            />
    LinearLayout>

** 附 :属性值获取正确性验证**

【5年Android从零复盘系列之六】Android自定义View(1):基础_第3张图片

3.自定义View分类

3.1 组合式

顾名思义,即xml文件中根布局使用RelativeLayout(同理其他布局控件),
内部使用其他View控件,布局摆放,组合成XxxView的原始布局。
然后,Java类继承根布局标签对应的容器类,覆写构造函数,并初始化各子View的变量。
是最常用、最稳妥、不易产生过度绘制、内存泄漏等问题。

Android自定义View(1):组合式

3.2 继承覆写

简而言之,即 如继承Button,修改默认background、state_press状态时按钮elevation值、取消默认最小高度56dp等。
也是最常用的、直接扩展/修改原生View功能

Android自定义View(2):继承改写

3.3 自绘式

强烈建议:熟悉View的绘制、Android事件传递、手势处理再入手自绘式。

方式:直接继承View ,重写绘制流程三步骤

  1. measure() 测量
  2. layout() 布局计算摆放坐标
  3. draw() 绘制

Android自定义View(3):自绘式

你可能感兴趣的:(Android,android,自定义View,TypeArray,TypeArray使用枚举,TypeArray使用位或运算)