您的位置:首页 > 移动开发 > Android开发

Android学习之自定义view(二)

2015-08-23 03:40 399 查看
在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_width和android: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方式来实现,敬请期待!~

源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: