Android效果/自定义

一:自定义view概述

2017-02-05  本文已影响22人  i冰点

1、自定义view

自定义view的一般步奏是:

1、 继承view、
2、 重写构造方法、
3、 重写onMeasure方法、
4、 重写onDraw方法。
5、 也可以使用自定义属性:

使用的优先级
直接在XML中定义>style定义>由defStyleAttr和defStyleRes指定的默认值>直接在Theme中指定的值
1、通过<declare-styleable>为自定义View添加属性
2、在xml中为相应的属性指定属性值

3、在运行时(一般为构造函数)获取属性值
我们要获取的属性值都是通过这个函数返回的TypedArray获得的

TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes){}

四个参数:

4、将获取到的属性值应用到View

1、构造函数

一般来说,你只需实现前两个

3、测量view的大小(onMeasure)

当宽高设置为match_parent、wrap_content时,系统帮我们测量的宽高都是match_parent的长度,所以在设置了wrap_content时,需要手动进行测量(重写onMeasure())。

在重新onMeasure方法时,需要注意 MeasureSpec 。 MeasureSpec封装了父布局传递给子布局的布局要求。一个MeasureSpec由大小和模式组成。

它有三种模式:
EXACTLY(精确): 父控件决定子控件的确切大小,子控件将被限定在给定的边界里而忽略它本身大小
AT_MOST(最多): 子控件至多达到指定大小的值,
UNSPECIFIED(未指定): 父控件不对子控件施加任何束缚,子元素可以得到任意想要的大小

最简单的映射关系是:

4、基本实现

自定义属性 定义(res/values/attrs.xml 下)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="SelfView">
        <attr name="innerColor" format="color"/>
    </declare-styleable>
    <attr name="defaultStyle" format="reference"/>
</resources>

使用,(res/values/style.xml 下)

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="defaultStyle">@style/defaultAttrStyle</item>
    </style>

    <style name="defaultAttrStyle">
        <item name="innerColor">@color/colorPrimary</item>
    </style>

    <style name="defaultResStyle">
        <item name="innerColor">@color/colorPrimary</item>
    </style>

</resources>

重写构造方法、onMeasure方法



public class SelfView extends View {
    private final int DEFAULT_COLOR= Color.RED;
    private final int DEFAULT_SIZE= 320;
    private int color;
    private int length;

    /**
     * 一般在直接New一个View的时候调用。
     */
    public SelfView(Context context) {
        this(context,null);
    }

    /**
     * 一般在layout文件中使用的时候会调用,关于它的所有属性(包括自定义属性)都会包含在attrs中传递进来。
     */
    public SelfView(Context context, AttributeSet attrs) {
        this(context, attrs,R.attr.defaultStyle);
    }

    public SelfView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //使用TypedArray 读取属性值
        TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.SelfView,defStyleAttr,R.style.defaultResStyle);
        color=typedArray.getColor(R.styleable.SelfView_innerColor,DEFAULT_COLOR);
        typedArray.recycle();
        init(context);
    }

/*    public SelfView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }*/
}

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getMeasureSpec(widthMeasureSpec),getMeasureSpec(heightMeasureSpec));
    }

    private int getMeasureSpec(int widthMeasureSpec) {
        int specMode=MeasureSpec.getMode(widthMeasureSpec);
        int specSize=MeasureSpec.getSize(widthMeasureSpec);
        int result=length;
        switch (specMode){
            case MeasureSpec.EXACTLY:
                result=specSize;
                break;
            case MeasureSpec.AT_MOST:
                result=Math.min(specSize,length);
                break;
            case MeasureSpec.UNSPECIFIED:
                break;
        }
        return result;
    }
}

参考:安卓自定义View进阶-分类与流程深入理解View的构造函数理解View的构造函数

2、绘图有关的类

1、Paint

Paint类用于定义绘图时的参数,主要包含颜色、文本、图形样式、位图模式、滤镜等几个方面。
1、图形样式包含绘制的图形是空心样式还是实心样式,同时还能指定落笔和收笔时的笔触效果。
Paint类与图形样式相关的方法有:

MITER
ROUND
BEVEL(FILL_AND_STROKE )
BEVEL(STROKE )
BEVEL(FILL)

参考:Android自定义组件开发详解 pdf

2、弧度和角度

角度=(弧度/Math.PI)*180
弧度转化为角度:Math.toDegrees()
角度转化为弧度:Math.toRadians()
反正切函數:Math.atan(),返回值是弧度
正切函数:Math.tan(),參數是弧度。

3、Canvas 的操作

⑴位移(translate)

 translate(float dx, float dy)

translate是坐标系的移动,是基于当前位置的移动,而不是每次基于屏幕左上角的(0,0)点移动

⑵缩放(scale)

scale(float sx, float sy)
scale(float sx, float sy, float px, float py)

缩放的中心默认为坐标原点 ,当缩放比例为负数的时候会根据缩放中心轴进行翻转

⑶旋转(rotate)

rotate(float degrees)
rotate(float degrees, float px, float py)

默认的旋转中心依旧是坐标原点。

所有的画布操作都只影响后续的绘制,对之前已经绘制过的内容没有影响。

(4)、保存save、回滚restore

大多数情况下只需要记住下面的步骤就可以了:

   save();      //保存状态
   ...          //具体操作
   restore();   //回滚到之前的状态

画布的操作是不可逆的,而且很多画布操作会影响后续的步骤,所以会对画布的一些状态进行保存和回滚。

通过旋转画布,可以得到如下效果:

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.GRAY);
        canvas.save();
        canvas.translate(width/2,height/2);
        canvas.drawCircle(0,0,outerRadius,linePaint);
        if(desBitmap!=null && !desBitmap.isRecycled()){
            for (int i=0;i<6;i++){
                canvas.drawBitmap(desBitmap,-innerRadius,outerRadius-innerRadius,null);
                canvas.rotate(60);
            }
        }
        canvas.restore();
    }
旋转画布

参考:安卓自定义View进阶-Canvas之画布操作

4、图层

参考:Android中Canvas绘图之PorterDuffXfermode使用及工作原理详解

</br></br>

上一篇 下一篇

猜你喜欢

热点阅读