Android:使用PathMeasure绘制动画效果的搜索按钮
2017-05-17 15:32
666 查看
首先上效果图:
![](https://img-blog.csdn.net/20170517152119157?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va3MxOTU4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
该搜索按钮有4种状态:
1. 默认状态:一个静态的放大镜;
2. 开始搜索状态:放大镜逐渐缩小为一个点;
3. 正在搜索状态:一个动态的圈;
4. 结束搜索状态:放大镜由一个点恢复初始状态。
此处点击一下模拟开始搜索,再点击一下搜索结束。
代码不多,直接全部贴上:
使用方法也很简单,放在xml布局文件中即可,注意需加上
参考文章: http://blog.csdn.net/u013831257/article/details/51565591
该搜索按钮有4种状态:
1. 默认状态:一个静态的放大镜;
2. 开始搜索状态:放大镜逐渐缩小为一个点;
3. 正在搜索状态:一个动态的圈;
4. 结束搜索状态:放大镜由一个点恢复初始状态。
此处点击一下模拟开始搜索,再点击一下搜索结束。
代码不多,直接全部贴上:
/** * 使用PathMeasure自定义的MySearchView. * Created by xxx on 17-5-15. */ public class MySearchView extends View { private static final int BG_COLOR = Color.parseColor("#FF37A1EC"); private static final int PADDING = 8; private Path bgPath; //圆角矩形背景 private Path searchPath; //放大镜Path private Path circlePath; //圆圈Path private static final int PAINT_WIDTH = 4; private PathMeasure measure; private Paint mPaint; private Paint mBgPaint; private static final int STATE_INIT = 0; //初始状态 private static final int STATE_STARTING = 1; //开始搜索状态 private static final int STATE_SEARCHING = 2; //正在搜索状态 private static final int STATE_ENDDING = 3; //结束搜索状态 //标记当前状态 private int state = STATE_INIT; public MySearchView(Context context) { super(context); } public MySearchView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MySearchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } private float searchLen; //放大镜路径总长度 private float circleLen; //大圆圈总长度 private void init() { measure = new PathMeasure(); //小圆的半径 int smallR = (mWidth - PADDING * 2) / 4; //中心点坐标 int centerXY = mWidth / 2; //放大镜 searchPath = new Path(); RectF rect1 = new RectF(centerXY - smallR, centerXY - smallR, centerXY + smallR, centerXY + smallR); searchPath.addArc(rect1, 45, 359.9f); //放大镜把手 searchPath.rLineTo(((float) (smallR * Math.sqrt(2) / 2)), ((float) (smallR * Math.sqrt(2) / 2))); searchPath_dst = new Path(); //大圆圈 circlePath = new Path(); RectF rect2 = new RectF(centerXY - smallR * 2, centerXY - smallR * 2, centerXY + smallR * 2, centerXY + smallR * 2); circlePath.addArc(rect2, 45, 359.9f); circlePath_dst = new Path(); //计算放大镜和圆圈的长度 measure.setPath(searchPath, false); searchLen = measure.getLength(); measure.setPath(circlePath, false); circleLen = measure.getLength(); bgPath = new Path(); RectF rect3 = new RectF(0, 0, mWidth, mHeight); bgPath.addRoundRect(rect3, 12, 12, Path.Direction.CW); mPaint = new Paint(); mPaint.setColor(Color.WHITE); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(PAINT_WIDTH); mPaint.setStyle(Paint.Style.STROKE); mBgPaint = new Paint(); mBgPaint.setColor(BG_COLOR); mBgPaint.setAntiAlias(true); mBgPaint.setStyle(Paint.Style.FILL); } //开始搜索 private void starting() { state = STATE_STARTING; measure.setPath(searchPath, false); //动画 ValueAnimator animator = ValueAnimator.ofFloat(0, 1).setDuration(START_DURATION); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float v = (float) animation.getAnimatedValue(); searchPath_dst.reset(); measure.getSegment(searchLen * v, searchLen, searchPath_dst, true); searchPath_dst.rLineTo(0, 0); invalidate(); if (v == 1) { searching(); //进入搜索状态 } } }); animator.start(); } private static final int START_DURATION = 1200; //开始搜索时动画周期 private static final int SEARCH_DURATION = 1200; //正在搜索时动画周期 //正在搜索 private void searching() { state = STATE_SEARCHING; measure.setPath(circlePath, false); ValueAnimator animator = ValueAnimator.ofFloat(0, 1).setDuration(SEARCH_DURATION); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float v = (float) animation.getAnimatedValue(); circlePath_dst.reset(); float stop = v * circleLen; float start = (float) (stop - ((0.5 - Math.abs(v - 0.5)) * 160f)); measure.getSegment(start, stop, circlePath_dst, true); circlePath_dst.rLineTo(0, 0); invalidate(); } }); animator.start(); postDelayed(new Runnable() { @Override public void run() { if (!isEnd) { searching(); } else { ending(); } } }, SEARCH_DURATION); } private boolean isEnd = false; //结束搜索 private void ending() { state = STATE_ENDDING; measure.setPath(searchPath, false); //动画 ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(START_DURATION); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float v = (float) animation.getAnimatedValue(); searchPath_dst.reset(); measure.getSegment(searchLen * v, searchLen, searchPath_dst, true); searchPath_dst.rLineTo(0, 0); if (v == 0) { state = STATE_INIT; isEnd = false; } invalidate(); } }); animator.start(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawSearchView(canvas); } private Path searchPath_dst; private Path circlePath_dst; private void drawSearchView(final Canvas canvas) { canvas.drawPath(bgPath, mBgPaint); if (state == STATE_INIT) { //初始状态,绘制静态的放大镜 canvas.drawPath(searchPath, mPaint); } else if (state == STATE_STARTING) { //开始搜索状态,绘制放大镜缩小到一个点的过程 canvas.drawPath(searchPath_dst, mPaint); } else if (state == STATE_SEARCHING) { //正在搜索状态,绘制外层大圆圈转圈 canvas.drawPath(circlePath_dst, mPaint); } else if (state == STATE_ENDDING) { //搜索结束,绘制放大镜恢复 canvas.drawPath(searchPath_dst, mPaint); } } //模拟搜索过程,点击一下开始搜索,再次点击搜索完成 @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_UP) { if (state == STATE_INIT) { starting(); } else if (state == STATE_SEARCHING) { isEnd = true; } return true; } return super.onTouchEvent(event); } private int mWidth, mHeight; @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); boolean first = (mWidth == 0); if (changed) { mWidth = getWidth(); mHeight = getHeight(); } if (first) { init(); } } }
使用方法也很简单,放在xml布局文件中即可,注意需加上
android:clickable="true"属性,否则组件无法接收
ACTION_UP事件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <com.chinark.appandroidtest.widget.MySearchView android:layout_width="50dp" android:layout_height="50dp" android:layout_margin="30dp" android:clickable="true" /> </LinearLayout>
参考文章: http://blog.csdn.net/u013831257/article/details/51565591
相关文章推荐
- Android使用XML Shape绘制带阴影效果的圆形按钮
- Android 使用 Path 实现搜索动态加载动画效果
- 【转】Android使用XML Shape绘制带阴影效果的圆形按钮
- Android使用XML Shape绘制带阴影效果的圆形按钮
- Android使用XML Shape绘制带阴影效果的圆形按钮
- android 使用Path实现搜索动态加载动画效果
- Android使用XML Shape绘制带阴影效果的圆形按钮
- Android使用XML Shape绘制带阴影效果的圆形按钮
- Android中使用Animation实现控件的动画效果以及Interpolator和AnimationListener的使用
- Android上Path应用左下角按钮动画效果demo原型
- Android控件的动画效果的实现及其AnimationListener和Interpolator的使用方法
- Android实现按钮从两边移到中间动画效果(网上整理)
- [Android]点击按钮进入下一个Activity时显示动画效果
- Android中的动画效果学习之二---Tween动画(使用XML文件进行配置动画效果)
- [HTML5-SVG]使用raphaeljs:绘制哆啦A梦并实现动画效果
- Android中使用Animation实现控件的动画效果以及Interpolator和AnimationListener的使用
- (转载)[Android]点击按钮进入下一个Activity时显示动画效果
- Android 实现 按钮从两边移到中间动画效果
- Android仿Path按钮动画效果 PathButton
- Android中的动画效果学习之二---Tween动画(使用XML文件进行配置动画效果)