一、自定义View基础
1、View的绘制流程
在了解自定义View之前,我们需要了解Android中View的绘制流程。View的绘制流程主要包括:
(1)测量(onMeasure):测量一个View的宽高,系统会根据这个宽高来确定View的布局位置。
(2)布局(onLayout):ViewGroup需要布局每个子View的位置,布局完成之后子View才可以被绘制。
(3)绘制(onDraw):如果这个View需要被绘制,那么系统就会调用onDraw方法,进行绘制。在绘制之前,系统会调用onMeasure和onLayout等方法来确定View的位置和大小。
2、继承View的自定义View
在使用自定义View之前,我们需要了解如何继承View类。以下是一个自定义View继承View类的示例代码:
public class MyView extends View { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); } }
二、自定义View的属性
1、自定义View属性的定义
Android中使用自定义属性可以在XML文件中设置一些属性值,可以让我们的View更加灵活。以下是一个自定义属性值的示例:
<declare-styleable name="MyView"> <attr name="my_text" format="string"/> </declare-styleable>
2、在XML文件中使用自定义属性
以下是一个在XML文件中使用自定义属性的示例:
3、在自定义View中获取属性值
在自定义View中获取自定义属性的值可以通过context.getTheme().obtainStyledAttributes方法获取。以下是一个在自定义View中获取属性值的示例:
public class MyView extends View { private String mMyText; public MyView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.getTheme().obtainStyledAttributes( attrs, R.styleable.MyView, 0, 0); try { mMyText = a.getString(R.styleable.MyView_my_text); } finally { a.recycle(); } } }
三、自定义View的绘制
1、绘制基本图形
在自定义View中,我们可以使用Canvas对象绘制基本的图形,如:线条、矩形、圆形等。以下是一个绘制圆形的示例代码:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.RED); canvas.drawCircle(100, 100, 50, paint); }
2、使用Path绘制复杂图形
如果需要绘制复杂的图形,除了基本形状外,我们可以使用Path对象进行绘制。Path的常用方法有:moveTo、lineTo、quadTo、cubicTo等,可以绘制出各种形状。以下是一个使用Path绘制心形的示例代码:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.RED); Path path = new Path(); path.moveTo(150, 150); path.quadTo(200, 100, 250, 150); path.quadTo(200, 200, 150, 250); path.quadTo(100, 200, 150, 150); canvas.drawPath(path, paint); }
四、自定义View的动画
在自定义View中,我们可以使用属性动画进行动画效果的实现。以下是一个使用属性动画实现位移效果的示例代码:
public class MyView extends View { private int mTranslationX = 0; public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void startAnimate() { ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 1000); valueAnimator.setDuration(1000); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mTranslationX = (int) animation.getAnimatedValue(); invalidate(); } }); valueAnimator.start(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.RED); canvas.drawRect(mTranslationX, 0, mTranslationX + getWidth(), getHeight(), paint); } }
五、自定义View的触摸事件
在自定义View中,我们可以使用触摸事件来实现交互效果。以下是一个处理触摸事件的示例代码:
public class MyView extends View { private Paint mPaint; private float mX, mY; public MyView(Context context) { super(context); init(); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(5); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.RED); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: mX = event.getX(); mY = event.getY(); break; case MotionEvent.ACTION_MOVE: float x = event.getX(); float y = event.getY(); Path path = new Path(); path.moveTo(mX, mY); path.lineTo(x, y); mX = x; mY = y; Canvas canvas = new Canvas(); canvas.drawPath(path, mPaint); break; } return true; } }