Add Code Source
This commit is contained in:
244
CustomView/Advance/Code/SearchView.java
Normal file
244
CustomView/Advance/Code/SearchView.java
Normal file
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* Author: GcsSloop
|
||||
* <p>
|
||||
* Created Date: 16/5/31
|
||||
* <p>
|
||||
* Copyright (C) 2016 GcsSloop.
|
||||
* <p>
|
||||
* GitHub: https://github.com/GcsSloop
|
||||
*/
|
||||
public class SearchView extends View {
|
||||
|
||||
// 画笔
|
||||
private Paint mPaint;
|
||||
|
||||
// View 宽高
|
||||
private int mViewWidth;
|
||||
private int mViewHeight;
|
||||
|
||||
// 这个视图拥有的状态
|
||||
public static enum State {
|
||||
NONE,
|
||||
STARTING,
|
||||
SEARCHING,
|
||||
ENDING
|
||||
}
|
||||
|
||||
// 当前的状态(非常重要)
|
||||
private State mCurrentState = State.NONE;
|
||||
|
||||
// 放大镜与外部圆环
|
||||
private Path path_srarch;
|
||||
private Path path_circle;
|
||||
|
||||
// 测量Path 并截取部分的工具
|
||||
private PathMeasure mMeasure;
|
||||
|
||||
// 默认的动效周期 2s
|
||||
private int defaultDuration = 2000;
|
||||
|
||||
// 控制各个过程的动画
|
||||
private ValueAnimator mStartingAnimator;
|
||||
private ValueAnimator mSearchingAnimator;
|
||||
private ValueAnimator mEndingAnimator;
|
||||
|
||||
// 动画数值(用于控制动画状态,因为同一时间内只允许有一种状态出现,具体数值处理取决于当前状态)
|
||||
private float mAnimatorValue = 0;
|
||||
|
||||
// 动效过程监听器
|
||||
private ValueAnimator.AnimatorUpdateListener mUpdateListener;
|
||||
private Animator.AnimatorListener mAnimatorListener;
|
||||
|
||||
// 用于控制动画状态转换
|
||||
private Handler mAnimatorHandler;
|
||||
|
||||
// 判断是否已经搜索结束
|
||||
private boolean isOver = false;
|
||||
|
||||
private int count = 0;
|
||||
|
||||
public SearchView(Context context) {
|
||||
super(context);
|
||||
|
||||
initPaint();
|
||||
|
||||
initPath();
|
||||
|
||||
initListener();
|
||||
|
||||
initHandler();
|
||||
|
||||
initAnimator();
|
||||
|
||||
// 进入开始动画
|
||||
mCurrentState = State.STARTING;
|
||||
mStartingAnimator.start();
|
||||
|
||||
}
|
||||
|
||||
private void initPaint() {
|
||||
mPaint = new Paint();
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mPaint.setColor(Color.WHITE);
|
||||
mPaint.setStrokeWidth(15);
|
||||
mPaint.setStrokeCap(Paint.Cap.ROUND);
|
||||
mPaint.setAntiAlias(true);
|
||||
}
|
||||
|
||||
private void initPath() {
|
||||
path_srarch = new Path();
|
||||
path_circle = new Path();
|
||||
|
||||
mMeasure = new PathMeasure();
|
||||
|
||||
// 注意,不要到360度,否则内部会自动优化,测量不能取到需要的数值
|
||||
RectF oval1 = new RectF(-50, -50, 50, 50); // 放大镜圆环
|
||||
path_srarch.addArc(oval1, 45, 359.9f);
|
||||
|
||||
RectF oval2 = new RectF(-100, -100, 100, 100); // 外部圆环
|
||||
path_circle.addArc(oval2, 45, -359.9f);
|
||||
|
||||
float[] pos = new float[2];
|
||||
|
||||
mMeasure.setPath(path_circle, false); // 放大镜把手的位置
|
||||
mMeasure.getPosTan(0, pos, null);
|
||||
|
||||
path_srarch.lineTo(pos[0], pos[1]); // 放大镜把手
|
||||
|
||||
Log.i("TAG", "pos=" + pos[0] + ":" + pos[1]);
|
||||
}
|
||||
|
||||
private void initListener() {
|
||||
mUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mAnimatorValue = (float) animation.getAnimatedValue();
|
||||
invalidate();
|
||||
}
|
||||
};
|
||||
|
||||
mAnimatorListener = new Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
// getHandle发消息通知动画状态更新
|
||||
mAnimatorHandler.sendEmptyMessage(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void initHandler() {
|
||||
mAnimatorHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
switch (mCurrentState) {
|
||||
case STARTING:
|
||||
// 从开始动画转换好搜索动画
|
||||
isOver = false;
|
||||
mCurrentState = State.SEARCHING;
|
||||
mStartingAnimator.removeAllListeners();
|
||||
mSearchingAnimator.start();
|
||||
break;
|
||||
case SEARCHING:
|
||||
if (!isOver) { // 如果搜索未结束 则继续执行搜索动画
|
||||
mSearchingAnimator.start();
|
||||
Log.e("Update", "RESTART");
|
||||
|
||||
count++;
|
||||
if (count>2){ // count大于2则进入结束状态
|
||||
isOver = true;
|
||||
}
|
||||
} else { // 如果搜索已经结束 则进入结束动画
|
||||
mCurrentState = State.ENDING;
|
||||
mEndingAnimator.start();
|
||||
}
|
||||
break;
|
||||
case ENDING:
|
||||
// 从结束动画转变为无状态
|
||||
mCurrentState = State.NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void initAnimator() {
|
||||
mStartingAnimator = ValueAnimator.ofFloat(0, 1).setDuration(defaultDuration);
|
||||
mSearchingAnimator = ValueAnimator.ofFloat(0, 1).setDuration(defaultDuration);
|
||||
mEndingAnimator = ValueAnimator.ofFloat(1, 0).setDuration(defaultDuration);
|
||||
|
||||
mStartingAnimator.addUpdateListener(mUpdateListener);
|
||||
mSearchingAnimator.addUpdateListener(mUpdateListener);
|
||||
mEndingAnimator.addUpdateListener(mUpdateListener);
|
||||
|
||||
mStartingAnimator.addListener(mAnimatorListener);
|
||||
mSearchingAnimator.addListener(mAnimatorListener);
|
||||
mEndingAnimator.addListener(mAnimatorListener);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
mViewWidth = w;
|
||||
mViewHeight = h;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
drawSearch(canvas);
|
||||
}
|
||||
|
||||
private void drawSearch(Canvas canvas) {
|
||||
|
||||
mPaint.setColor(Color.WHITE);
|
||||
|
||||
|
||||
canvas.translate(mViewWidth / 2, mViewHeight / 2);
|
||||
|
||||
canvas.drawColor(Color.parseColor("#0082D7"));
|
||||
|
||||
switch (mCurrentState) {
|
||||
case NONE:
|
||||
canvas.drawPath(path_srarch, mPaint);
|
||||
break;
|
||||
case STARTING:
|
||||
mMeasure.setPath(path_srarch, false);
|
||||
Path dst = new Path();
|
||||
mMeasure.getSegment(mMeasure.getLength() * mAnimatorValue, mMeasure.getLength(), dst, true);
|
||||
canvas.drawPath(dst, mPaint);
|
||||
break;
|
||||
case SEARCHING:
|
||||
mMeasure.setPath(path_circle, false);
|
||||
Path dst2 = new Path();
|
||||
float stop = mMeasure.getLength() * mAnimatorValue;
|
||||
float start = (float) (stop - ((0.5 - Math.abs(mAnimatorValue - 0.5)) * 200f));
|
||||
mMeasure.getSegment(start, stop, dst2, true);
|
||||
canvas.drawPath(dst2, mPaint);
|
||||
break;
|
||||
case ENDING:
|
||||
mMeasure.setPath(path_srarch, false);
|
||||
Path dst3 = new Path();
|
||||
mMeasure.getSegment(mMeasure.getLength() * mAnimatorValue, mMeasure.getLength(), dst3, true);
|
||||
canvas.drawPath(dst3, mPaint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user