您的位置:首页 > 产品设计 > UI/UE

Android高级UICanvas和Path使用——自定义SearchView搜索框动画

2017-07-13 14:46 459 查看
预览:



一、实现思路:

圆形搜索框长度应该与下面的横线的长度相同

整个图形分成三部分:圆、与圆相连的手柄、与手柄相连的横线

动画过程中圆与手柄是一体的,其长度与下面的横线的长度成相反的关系

二、实现步骤:

1,初始化画布及画笔

2,分别绘制圆,手柄及下边的横线

3,启动动画,更改相应的比例参数实现该效果

1,初始化画布及画笔:

path = new Path();
paint = new Paint();
paint.setColor(Color.RED);
paint.setFlags(Paint.DITHER_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(8);
paint.setAntiAlias(true);
paint.setDither(true);


2、计算总的路径的长度

round = (float) (2*Math.PI*radius);
length = round+lLength;


round为圆的周长,lLength为定义的手柄的长度,length则为总长度,也就是下边横线的总长度

3、重新ondraw方法开始绘制

绘制圆弧使用path.addArc(RectF oval, float startAngle, float sweepAngle)方法:

path.addArc方法用于绘制圆弧,这个圆弧取自RectF矩形的内接椭圆上的一部分,圆弧长度由后两个参数决定

startAngle:起始位置的角度值

sweepAngle:旋转的角度值

@Override
protected void onDraw(Canvas canvas) {
path.reset();
//mpro 用于更改圆弧的角度,-360*mpro 为顺时针旋转
if(mpro>0){
path.addArc(mRectF,45,-360*mpro);
}

canvas.drawPath(path,paint);
canvas.save();
//绘制手柄的直线,此处也可以将画布旋转45度以后直接绘制,此处采用正切值计算起始点的坐标
canvas.drawLine(
pointF.x+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH))-(float)(Math.sin(2*Math.PI/360*45)*lLength),
pointF.y+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH))-(float)(Math.sin(2*Math.PI/360*45)*lLength),
pointF.x+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH)),
pointF.y+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH)),
paint);
//绘制下边的直线
canvas.drawLine(pointF.x+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH))-lineLen,
pointF.y+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH)),
pointF.x+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH)),
pointF.y+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH)),
paint);
}


Math.sin(2*Math.PI/360*45):此处计算正切值传入的参数是弧度值,而不是角度值

4、动画

展开动画

public void startViewAnimation(){
if(valueAnimator!=null&&valueAnimator.isRunning()){
return;
}
valueAnimator = ValueAnimator.ofFloat(0,length);
valueAnimator.setDuration((long) (2000));
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float  curLen = (float) animation.getAnimatedValue();
float lingTh = curLen -round;
//修改圆弧坐标点
pointF.x+=2;
mRectF = new RectF(pointF.x-radius,pointF.y-radius,pointF.x+radius,pointF.y+radius);
if(lingTh>0){
lLength = (int) (80-lingTh);
}else{
if(curLen<=round){
mpro= 1-curLen/round - 0.009f;
}
}
lineLen = curLen;
invalidate();
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
lLength = 80;
pointF.x = 100;
}

@Override
public void onAnimationEnd(Animator animation) {
endViewAnimation();
}

@Override
public void onAnimationCancel(Animator animation) {

}

@Override
public void onAnimationRepeat(Animator animation) {

}
});
valueAnimator.start();


还原动画

public void endViewAnimation(){
ValueAnimator valueAnimator = ValueAnimator.ofFloat(length,0);
valueAnimator.setDuration((long) (2000));
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float  curLen = (float) animation.getAnimatedValue();
float lingTh = curLen -round;
pointF.x-=2;
mRectF = new RectF(pointF.x-radius,pointF.y-radius,pointF.x+radius,pointF.y+radius);
if(lingTh>0){
lLength = (int) (80-lingTh);
}else{
if(curLen<=round){
mpro= 1-curLen/round;
}
}
lineLen = curLen;
invalidate();
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}

@Override
public void onAnimationEnd(Animator animation) {
startViewAnimation();
}

@Override
public void onAnimationCancel(Animator animation) {

}

@Override
public void onAnimationRepeat(Animator animation) {

}
});
valueAnimator.start();
}


最后在MotionEvent.ACTION_DOWN 的时候启动动画就行了

完整代码:

package com.example.flowproject;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;

public class DrawView extends View {
private float round;
private Path path;
private Paint paint = null;
private int VIEW_WIDTH = 800;
private int VIEW_HEIGHT = 600;
Bitmap cacheBitmap = null;
//定义缓冲区Cache的Canvas对象
Canvas cacheCanvas = null;
private RectF mRectF;
public float mpro = -1;
float length;
float lineLen;
PointF pointF;
int radius = 50;
int lLength = LINE_LENGTH;
private static final int LINE_LENGTH = 80;
private ValueAnimator valueAnimator;

public DrawView(Context context) {
this(context,null);
pointF = new PointF(100,800);
mRectF = new RectF(pointF.x-radius,pointF.y-radius,pointF.x+radius,pointF.y+radius);
mpro= 0;
}

public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
//创建一个与该VIew相同大小的缓冲区
cacheBitmap = Bitmap.createBitmap(VIEW_WIDTH,VIEW_HEIGHT,Bitmap.Config.ARGB_8888);
//创建缓冲区Cache的Canvas对象
cacheCanvas = new Canvas();
path = new Path();
//设置cacheCanvas将会绘制到内存的bitmap上
cacheCanvas.setBitmap(cacheBitmap);
paint = new Paint();
paint.setColor(Color.RED);
paint.setFlags(Paint.DITHER_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(8);
paint.setAntiAlias(true);
paint.setDither(true);

round = (float) (2*Math.PI*radius); length = round+lLength;
}

@Override
protected void onDraw(Canvas canvas) {
path.reset();
//mpro为圆的角度的进度,当mpro==0时,则整个圆绘制完成
if(mpro>0){
path.addArc(mRectF,45,-360*mpro);
}
paint.setStrokeCap(Paint.Cap.ROUND);
canvas.drawPath(path,paint);
canvas.save();
canvas.drawLine(
pointF.x+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH))-(float)(Math.sin(2*Math.PI/360*45)*lLength),
pointF.y+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH))-(float)(Math.sin(2*Math.PI/360*45)*lLength),
pointF.x+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH)),
pointF.y+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH)),
paint);

canvas.drawLine(pointF.x+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH))-lineLen,
pointF.y+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH)),
pointF.x+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH)),
pointF.y+(float)(Math.sin(2*Math.PI/360*45)*(radius+LINE_LENGTH)),
paint);
}

public void startViewAnimation(){
if(valueAnimator!=null&&valueAnimator.isRunning()){
return;
}
valueAnimator = ValueAnimator.ofFloat(0,length);
valueAnimator.setDuration((long) (2000));
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float curLen = (float) animation.getAnimatedValue();
float lingTh = curLen -round;
pointF.x+=2;
mRectF = new RectF(pointF.x-radius,pointF.y-radius,pointF.x+radius,pointF.y+radius);
if(lingTh>0){
lLength = (int) (80-lingTh);
}else{
if(curLen<=round){
mpro= 1-curLen/round - 0.009f;
}
}
lineLen = curLen;
invalidate();
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
lLength = 80;
pointF.x = 100;
}

@Override
public void onAnimationEnd(Animator animation) {
endViewAnimation();
}

@Override
public void onAnimationCancel(Animator animation) {

}

@Override
public void onAnimationRepeat(Animator animation) {

}
});
valueAnimator.start();
}

public void endViewAnimation(){ ValueAnimator valueAnimator = ValueAnimator.ofFloat(length,0); valueAnimator.setDuration((long) (2000)); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float curLen = (float) animation.getAnimatedValue(); float lingTh = curLen -round; pointF.x-=2; mRectF = new RectF(pointF.x-radius,pointF.y-radius,pointF.x+radius,pointF.y+radius); if(lingTh>0){ lLength = (int) (80-lingTh); }else{ if(curLen<=round){ mpro= 1-curLen/round; } } lineLen = curLen; invalidate(); } }); valueAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { startViewAnimation(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); valueAnimator.start(); }

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
startViewAnimation();
break;
}
return true;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: