Android学习之自定义view(二)

在csdn博客上看到卡片重叠的效果,由于最近一直在学自定义view,所以想着这个卡片效果可以通过自定义view来实现,于是花了一些时间来实现,这也是学习自定义view的第二篇。

按照国际惯例,自定义view三部曲走起来:

1.在values文件夹下创建attrs.xml文件,内容如下:

<resources>
    <declare-styleable name="MyCustomView2">
        <attr name="firstCardColor" format="color" />
        <attr name="secCardColor" format="color" />
        <attr name="thirdCardColor" format="color" />
    </declare-styleable>
</resources>

三个属性分别代表三张卡片的颜色


2.写一个类继承自view,并在构造函数中获取上面定义的属性

public MyCustomView2(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView2);
        for(int i=0;i<ta.getIndexCount();i++){
            int attr = ta.getIndex(i);
            switch(attr){
            case R.styleable.MyCustomView2_firstCardColor :
                firstCardColor = ta.getColor(attr, Color.BLUE); //未设置颜色的时候默认为蓝色
                break;
            case R.styleable.MyCustomView2_secCardColor :
                secCardColor = ta.getColor(attr, Color.RED); //未设置颜色的时候默认为红色
                break;
            case R.styleable.MyCustomView2_thirdCardColor :
                thirdCardColor = ta.getColor(attr, Color.GREEN);//未设置颜色的时候默认为绿色
                break;
            }
        }
        ta.recycle();
        
        mPaint = new Paint();
    }


3.重写[onMeasure]onDraw方法

在这里有两种情况,重写onMeasure和不重写onMeasure

a).不重写onMeasure(使用系统自带的测量方法):

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

接着重写onDraw方法

    @Override
    protected void onDraw(Canvas canvas) {
        
        //将组件宽度的1/4和高度的1/3作为第一张卡片的宽和高
        width = getMeasuredWidth() / 4;
        height = getMeasuredHeight() / 3;
        
        /**
         * 若没有指定android:padding属性,则取组件大小的1/8作为卡片之间的间距
         * 否则就取它们四个值的平均值
         */
        if(getPaddingLeft() == 0 || getPaddingRight() == 0
                || getPaddingTop() == 0 || getPaddingBottom() == 0){
            mStep = getMeasuredWidth() / 8;//将组件的1/8作为卡片之间的间距
        }else{
            mStep = (getPaddingLeft() + getPaddingRight() + getPaddingTop() + getPaddingBottom()) / 4;//取平均值作为间距
        }
                
        //画第一张卡片
        mPaint.setColor(firstCardColor);
        canvas.drawRect(0, 0, width, height, mPaint);  
        
        //画第二张卡片
        mPaint.setColor(secCardColor);
        canvas.drawRect(mStep, mStep, width + mStep, height + mStep, mPaint);
        
        //画第三张卡片
        mPaint.setColor(thirdCardColor);
        canvas.drawRect(mStep * 2, mStep * 2, width + mStep * 2, height + mStep * 2, mPaint);
    }

在这个方法中,主要就是绘制想要的效果了。绘制的内容始终在通过测量的view大小之中

在画第一个卡片的时候,起始的left和top坐标可以根据需要将其设置到组件的任何位置。

然后就是在布局文件中使用这个自定义的view

注:使用之前需要添加namespace,在这里,我的namespace是:

xmlns:custom="http://schemas.android.com/apk/res/com.example.mycustomview2"

<com.example.mycustom.view.MyCustomView2
        android:layout_width="300dp"
        android:layout_height="300dp"

        android:layout_margin="10dp"
        android:layout_centerInParent="true"
        android:background="#000000"
        custom:firstCardColor="#0066CC"
        custom:secCardColor="#ff0000"
        custom:thirdCardColor="#009933"/>

此时的效果是:


<com.example.mycustom.view.MyCustomView2
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        android:layout_centerInParent="true"
        android:background="#000000"
        custom:firstCardColor="#0066CC"
        custom:secCardColor="#ff0000"
        custom:thirdCardColor="#009933"/>

改为warp_parent也是相同的效果


b).重写onMeasure

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = 0;  //组件的宽度
        int height = 0; //组件的高度
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        
        /**
         * 组件宽度和高度的布局为MATCH_PARENT或精确的值的时,使用系统测试的结果;
         * 否则使用在资源文件中定义的组件的大小
         */
        if(widthMode == MeasureSpec.EXACTLY){  //一般为MATCH_PARENT和精确的值
            width = widthSize;
        }else if(heightMode == MeasureSpec.AT_MOST){  //一般为WARP_PARENT

            //从资源文件中获取默认的宽度         

            width = getResources().getDimensionPixelSize(R.dimen.custom_view_size);  
        }
        if(heightMode == MeasureSpec.EXACTLY){
            height = heightSize;
        }else if(heightMode == MeasureSpec.AT_MOST){

             //从资源文件中获取默认的高度

             height = getResources().getDimensionPixelSize(R.dimen.custom_view_size); 
        }
        
        setMeasuredDimension(width, height);
    }


<com.example.mycustom.view.MyCustomView2
        android:layout_width="match_parent"
        android:layout_height="match_parent"

        android:layout_margin="10dp"
        android:layout_centerInParent="true"
        android:background="#000000"
        custom:firstCardColor="#0066CC"
        custom:secCardColor="#ff0000"
        custom:thirdCardColor="#009933"/>

效果如下:


<com.example.mycustom.view.MyCustomView2
        android:layout_width="300dp"
        android:layout_height="300dp"

        android:layout_margin="10dp"
        android:layout_centerInParent="true"
        android:background="#000000"
        custom:firstCardColor="#0066CC"
        custom:secCardColor="#ff0000"
        custom:thirdCardColor="#009933"/>

效果如下:


由此可见,不管是否重写onMeasure方法,android:layout_widthandroid:layout_height为match_parent或者精确值的时候效果是一样的,关键是当为warp_parent的时候。

<com.example.mycustom.view.MyCustomView2
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:layout_margin="10dp"
        android:layout_centerInParent="true"
        android:background="#000000"
        custom:firstCardColor="#0066CC"
        custom:secCardColor="#ff0000"
        custom:thirdCardColor="#009933"/>

效果如下:

之所以会出现这样的效果是因为,在重写onMeasure方法的时候,如果定义的宽度和高度为warp_parent的话(对应MeasureSpec.AT_MOST),就从dimens.xml文件中获取一个大小,用于决定view的大小。


至此,卡片重叠的效果已经实现。这个案例是将三张卡片作为一个view,而不是单独的由三个view构成,因此,要想还是实现同样的效果,可以自定ViewGroup来实现,所以下一篇就来阐述通过自定义ViewGroup方式来实现,敬请期待!~


源码下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值