前言
Android系统已经为我们提供了有各种功能的View了,如显示文本的,图片的,还提供了一些ViewGroup控制子View显示的,如ListView,LinearLayout,RelativeLayout,然而呢,面对复杂多变的产品需求,这些还是无法满足。在黑马的课程中,我们有4天的专门讲解自定义View知识的课程,也在4个项目中去穿插的讲解自定义控件,可以说算是比较全面了。今天我从几个方面综合讲解下如何去自定义出你想要的View。
分析
当我们说要自定义一个View时,其实你是在想自定义这个View的这些方面:
- 你想自定义这个View上显示的内容
- 你想自定义这个View中子View的摆放位置
- 你想让这个View跟随手指的移动进行某些变化
所以,我们就从这4个方面来学习如何自定义效果。
实践
如何自定义View显示的内容
首先,你要知道想自定义View应该去继承自谁,到底是View还是ViewGroup;如果你只是想自定义单个View的内容,那么应该继承自View;如果你想自定义一个布局的显示内容,那么应该继承ViewGroup。
现在我们设定需求,要做一个显示一个红色圆形的View,那么你要继承View,重写onDraw方法,因为onDraw方法就是允许自定义显示内容的方法。我们在里面绘制一个圆,代码如下:
public class CircleView extends View{
Paint paint = new Paint();
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
paint.setColor(Color.RED);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(getWidth()/2, getHeight()/2, 50, paint);
}
}
效果图如下:
下面呢,我们在设一个复杂点的需求,要求自定义一个显示一个红色对勾的View,这时候要绘制对勾,需要借助Path类来勾勒。代码如下:
public class TickView extends View{
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Path path = new Path();
public TickView(Context context, AttributeSet attrs) {
super(context, attrs);
paint.setColor(Color.RED);
paint.setStrokeWidth(8);
paint.setStyle(Style.STROKE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path.moveTo(100, 100);
path.lineTo(140, 140);
path.lineTo(220, 60);
canvas.drawPath(path, paint);
}
}
效果图如下:
Ok,以上这些就是如何自定义View内容的技巧,当然如果你想绘制更加复杂的效果,那就要仔细学习一下Canvas和Path的api了。
如何自定义View中子View的位置
此处由于你要自定义的View中是包含子View的,那么你应该继承ViewGroup,并且通常情况下,我们为了省去实现onMeasure方法,那么就可以继承系统提供的某个布局,如FrameLayout。自定义子View的位置,那么需要重写onLayout方法了,该方法是允许你随意指定子View位置的。
现在我们设定需求,要求实现一个ViewGroup,它的子View是从右往左边排列的。代码如下:
public class RightLayout extends FrameLayout{
public RightLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
View child1 = getChildAt(0);
View child2 = getChildAt(1);
child1.layout(getMeasuredWidth()-child1.getMeasuredWidth(),
getPaddingTop(),getMeasuredWidth(),
getPaddingTop()+child1.getMeasuredHeight());
child2.layout(child1.getLeft()-child2.getMeasuredWidth(), getPaddingTop(),getMeasuredWidth()-child1.getMeasuredWidth(),
getPaddingTop()+child2.getMeasuredHeight());
}
}
效果图如下:
总结,通过layout的方法来控制View的位置,这个属于比较简单的。
如何让View随手指移动进行变化
要实现这个,那么你需要完成2个点:
- 监听手指移动的距离
- 让View进行一些变化
对于第一点,监听手指移动的距离,这个很简单,可以重写onTouch方法,获取手指移动距离,也可以借助ViewDragHelper所封装的方法来监听手指的移动。对于通过onTouch方法来获取手指移动距离的代码略过,下面展示一下通过ViewDragHelper来获取手指距离的代码,你需要熟悉一下ViewDragHelper的用法才能看懂下面的代码,clampViewPositionHorizontal方法的dx参数就是手指移动的距离,代码如下:
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//dx就是手指移动的距离
return super.clampViewPositionHorizontal(child, left, dx);
}
所以,获取手指移动距离很简单,我们主要把精力放在让View进行一些变化上。
这些变化一般是的是缩放,平移,透明,旋转的变化,这些变化Android都为我们提供了对应的操作View属性的方法,代码如下:
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//dx就是手指移动的距离
//平移
view.setTranslationX(dx);
//缩放
view.setScaleX(0.1f);
view.setScaleY(0.1f);
//透明
view.setAlpha(0.1f);
//旋转
view.setRotation(180);
return super.clampViewPositionHorizontal(child, left, dx);
}
当然如果你需要让View执行某些动画效果,那么你要借助属性动画了,如果你想自定义动画效果,那么就需要使用ValueAnimator,或者继承Animaton类实现自定义动画。
总结
以上总结了我们自定义View中最常用的情景,当然还有其他很多情况。不过我们可以在这3种基础上举一反三。遇到复杂的效果,就分离模块,一点一点实现,自定义View也就那么点事。
本文版权归传智播客Android培训学院所有,欢迎转载,转载请注明作者出处。谢谢!
作者:传智播客Android培训学院
首发:http://www.itcast.cn/Android