Android通过Path实现复杂效果(搜索按钮+时钟的实现 )

Path :

在Android中复杂的图形的绘制绝大多数是通过path来实现,比如绘制一条曲线,然后让一个物体随着这个曲线运动,比如搜索按钮,比如一个简单时钟的实现:

那么什么是path呢!

定义:path  就是路径,就是图形的路径的集合,它里边包含了路径里边的坐标点,等等的属性。我们可以获取到任意点的坐标,正切值。


那么要获取Path上边所有点的坐标还需要用到一个类,PathMeasure;


PathMesure:



PathMeasure是一个用来测量Path的类,主要有以下方法:

构造方法

方法名 释义
PathMeasure() 创建一个空的PathMeasure
PathMeasure(Path path, boolean forceClosed) 创建 PathMeasure 并关联一个指定的Path(Path需要已经创建完成)。

公共方法

返回值 方法名 释义
void setPath(Path path, boolean forceClosed) 关联一个Path
boolean isClosed() 是否闭合
float getLength() 获取Path的长度
boolean nextContour() 跳转到下一个轮廓
boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) 截取片段
boolean getPosTan(float distance, float[] pos, float[] tan) 获取指定长度的位置坐标及该点切线值
boolean getMatrix(float distance, Matrix matrix, int flags) 获取指定长度的位置坐标及该点Matrix

可以看到,这个就等于是一个Path的一个工具类,方法很简单,那么就开始我们所要做的按钮跟时钟的开发吧

(1)搜索按钮:

首先上图:

要实现这个功能首先要把他分解开来做;

创建搜索按钮的path路径,然后创建外圈旋转的path,


  1. public void initPath(){  
  2.       mPath_search = new Path();  
  3.       mPath_circle = new Path();  
  4.   
  5.       mMeasure = new PathMeasure();  
  6.   
  7.       // 注意,不要到360度,否则内部会自动优化,测量不能取到需要的数值  
  8.       RectF oval1 = new RectF(-50, -50, 50, 50);          // 放大镜圆环  
  9.       mPath_search.addArc(oval1, 45, 359.9f);  
  10.   
  11.       RectF oval2 = new RectF(-100, -100, 100, 100);      // 外部圆环  
  12.       mPath_circle.addArc(oval2, 45, -359.9f);  
  13.   
  14.       float[] pos = new float[2];  
  15.   
  16.       mMeasure.setPath(mPath_circle, false);               // 放大镜把手的位置  
  17.       mMeasure.getPosTan(0, pos, null);  
  18.   
  19.       mPath_search.lineTo(pos[0], pos[1]);                 // 放大镜把手  
  20.   
  21.       Log.i("TAG", "pos=" + pos[0] + ":" + pos[1]);  
  22.   
  23.   }  

我们要的效果就是点击搜索按钮的时候开始从按钮变为旋转,然后搜索结束以后变为搜索按钮。

所以我们可以确定有四种状态:

[java] view plain copy

 print?

  1. public   enum  Seach_State{  
  2.     START,END,NONE,SEARCHING  
  3.  }  

 然后根据状态来进行动态绘制path,动态绘制path就要使用到PathMeasure测量当前path的坐标,然后进行绘制。

[java] view plain copy

 print?

  1. private void drawPath(Canvas c) {  
  2.     c.translate(mWidth / 2, mHeight / 2);  
  3.     switch (mState){  
  4.   
  5.         case NONE:  
  6.             c.drawPath(mPath_search,mPaint);  
  7.             break;  
  8.   
  9.         case START:  
  10.             mMeasure.setPath(mPath_search,true);  
  11.             Path path = new Path();  
  12.             mMeasure.getSegment(mMeasure.getLength() * curretnAnimationValue,mMeasure.getLength(),path, true);  
  13.             c.drawPath(path,mPaint);  
  14.             break;  
  15.   
  16.         case SEARCHING:  
  17.             mMeasure.setPath(mPath_circle,true);  
  18.             Path path_search = new Path();  
  19.             mMeasure.getSegment(mMeasure.getLength()*curretnAnimationValue -30,mMeasure.getLength()*curretnAnimationValue,path_search,true);  
  20.             c.drawPath(path_search,mPaint);  
  21.             break;  
  22.   
  23.         case END:  
  24.             mMeasure.setPath(mPath_search,true);  
  25.             Path path_view = new Path();  
  26.   
  27.             mMeasure.getSegment(0,mMeasure.getLength()*curretnAnimationValue,path_view,true);  
  28.             c.drawPath(path_view,mPaint);  
  29.             break;  
  30.     }  
  31.   
  32. }  

然后就是需要通过使用属性动画来返回当前该绘制的百分百,通过这个值来进行计算要绘制的path。

下边是整个代码:

[java] view plain copy

 print?

  1. package com.duoku.platform.demo.canvaslibrary.attract.view;  
  2.   
  3. import android.animation.Animator;  
  4. import android.animation.ValueAnimator;  
  5. import android.content.Context;  
  6. import android.graphics.Canvas;  
  7. import android.graphics.Color;  
  8. import android.graphics.Paint;  
  9. import android.graphics.Path;  
  10. import android.graphics.PathMeasure;  
  11. import android.graphics.RectF;  
  12. import android.util.AttributeSet;  
  13. import android.util.Log;  
  14. import android.view.View;  
  15.   
  16. /** 
  17.  * Created by chenpengfei_d on 2016/9/7. 
  18.  */  
  19. public class SearchView extends View {  
  20.     private Paint mPaint;  
  21.     private Context mContext;  
  22.     private Path mPath_circle;  
  23.     private Path mPath_search;  
  24.     private PathMeasure mMeasure;  
  25.     private ValueAnimator mValueAnimator_search;  
  26.     private long  defaultduration=3000;  
  27.     private float curretnAnimationValue;  
  28.     private Seach_State mState = Seach_State.SEARCHING;  
  29.     public SearchView(Context context) {  
  30.         super(context);  
  31.         init(context);  
  32.     }  
  33.   
  34.     public SearchView(Context context, AttributeSet attrs) {  
  35.         super(context, attrs);  
  36.         init(context);  
  37.     }  
  38.   
  39.     public SearchView(Context context, AttributeSet attrs, int defStyleAttr) {  
  40.         super(context, attrs, defStyleAttr);  
  41.         init(context);  
  42.     }  
  43.   
  44.     public void init(Context context){  
  45.         this.mContext = context;  
  46.         initPaint();  
  47.         initPath();  
  48.         initAnimation();  
  49.   
  50.     }  
  51.     public void initPaint(){  
  52.         mPaint = new Paint();  
  53.         mPaint.setDither(true);  
  54.         mPaint.setStrokeCap(Paint.Cap.ROUND);//设置笔头效果  
  55.         mPaint.setAntiAlias(true);  
  56.         mPaint.setColor(Color.RED);  
  57.         mPaint.setStrokeWidth(3);  
  58.         mPaint.setStyle(Paint.Style.STROKE);  
  59.     }  
  60.   
  61.     public void initPath(){  
  62.         mPath_search = new Path();  
  63.         mPath_circle = new Path();  
  64.   
  65.         mMeasure = new PathMeasure();  
  66.   
  67.         // 注意,不要到360度,否则内部会自动优化,测量不能取到需要的数值  
  68.         RectF oval1 = new RectF(-50, -50, 50, 50);          // 放大镜圆环  
  69.         mPath_search.addArc(oval1, 45, 359.9f);  
  70.   
  71.         RectF oval2 = new RectF(-100, -100, 100, 100);      // 外部圆环  
  72.         mPath_circle.addArc(oval2, 45, -359.9f);  
  73.   
  74.         float[] pos = new float[2];  
  75.   
  76.         mMeasure.setPath(mPath_circle, false);               // 放大镜把手的位置  
  77.         mMeasure.getPosTan(0, pos, null);  
  78.   
  79.         mPath_search.lineTo(pos[0], pos[1]);                 // 放大镜把手  
  80.   
  81.         Log.i("TAG", "pos=" + pos[0] + ":" + pos[1]);  
  82.   
  83.     }  
  84.   
  85.     public void initAnimation(){  
  86.         mValueAnimator_search = ValueAnimator.ofFloat(0f,1.0f).setDuration(defaultduration);  
  87.   
  88.         mValueAnimator_search.addUpdateListener(updateListener);  
  89.   
  90.         mValueAnimator_search.addListener(animationListener);  
  91.     }  
  92.     private ValueAnimator.AnimatorUpdateListener updateListener = new ValueAnimator.AnimatorUpdateListener() {  
  93.         @Override  
  94.         public void onAnimationUpdate(ValueAnimator animation) {  
  95.             curretnAnimationValue = (float) animation.getAnimatedValue();  
  96.             invalidate();  
  97.         }  
  98.     };  
  99.   
  100.     private Animator.AnimatorListener animationListener = new Animator.AnimatorListener() {  
  101.         @Override  
  102.         public void onAnimationStart(Animator animation) {  
  103.   
  104.         }  
  105.   
  106.         @Override  
  107.         public void onAnimationEnd(Animator animation) {  
  108.                 if(mState ==Seach_State.START){  
  109.                     setState(Seach_State.SEARCHING);  
  110.                 }  
  111.         }  
  112.   
  113.         @Override  
  114.         public void onAnimationCancel(Animator animation) {  
  115.   
  116.         }  
  117.   
  118.         @Override  
  119.         public void onAnimationRepeat(Animator animation) {  
  120.   
  121.         }  
  122.     };  
  123.     @Override  
  124.     protected void onDraw(Canvas canvas) {  
  125.         super.onDraw(canvas);  
  126.   
  127.         drawPath(canvas);  
  128.     }  
  129.     private int mWidth,mHeight;  
  130.     @Override  
  131.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  132.         super.onSizeChanged(w, h, oldw, oldh);  
  133.         mWidth = w;  
  134.         mHeight = h;  
  135.   
  136.     }  
  137.   
  138.     private void drawPath(Canvas c) {  
  139.         c.translate(mWidth / 2, mHeight / 2);  
  140.         switch (mState){  
  141.   
  142.             case NONE:  
  143.                 c.drawPath(mPath_search,mPaint);  
  144.                 break;  
  145.   
  146.             case START:  
  147.                 mMeasure.setPath(mPath_search,true);  
  148.                 Path path = new Path();  
  149.                 mMeasure.getSegment(mMeasure.getLength() * curretnAnimationValue,mMeasure.getLength(),path, true);  
  150.                 c.drawPath(path,mPaint);  
  151.                 break;  
  152.   
  153.             case SEARCHING:  
  154.                 mMeasure.setPath(mPath_circle,true);  
  155.                 Path path_search = new Path();  
  156.                 mMeasure.getSegment(mMeasure.getLength()*curretnAnimationValue -30,mMeasure.getLength()*curretnAnimationValue,path_search,true);  
  157.                 c.drawPath(path_search,mPaint);  
  158.                 break;  
  159.   
  160.             case END:  
  161.                 mMeasure.setPath(mPath_search,true);  
  162.                 Path path_view = new Path();  
  163.   
  164.                 mMeasure.getSegment(0,mMeasure.getLength()*curretnAnimationValue,path_view,true);  
  165.                 c.drawPath(path_view,mPaint);  
  166.                 break;  
  167.         }  
  168.   
  169.     }  
  170.   
  171.   
  172.     public void setState(Seach_State state){  
  173.         this.mState = state;  
  174.         startSearch();  
  175.     }  
  176.   
  177.     public void startSearch(){  
  178.         switch (mState){  
  179.             case START:  
  180.                 mValueAnimator_search.setRepeatCount(0);  
  181.                 break;  
  182.   
  183.             case SEARCHING:  
  184.                 mValueAnimator_search.setRepeatCount(ValueAnimator.INFINITE);  
  185.                 mValueAnimator_search.setRepeatMode(ValueAnimator.REVERSE);  
  186.                 break;  
  187.   
  188.             case END:  
  189.                 mValueAnimator_search.setRepeatCount(0);  
  190.                 break;  
  191.         }  
  192.         mValueAnimator_search.start();  
  193.     }  
  194.    public   enum  Seach_State{  
  195.        START,END,NONE,SEARCHING  
  196.     }  
  197. }  

(学习的点:path可以组合,可以把不同的path放置到一个path里边,然后进行统一的绘制)

(2)时钟:

效果:

说一下时钟的思路啊,网上很多时钟都是通过Canvas绘制基本图形实现的,没有通过path来实现的,使用path实现是为了以后更加灵活的控制时钟的绘制效果,比如我们要让最外边的圆圈逆时针旋转,还比如在上边添加些小星星啥的,用path的话会更加灵活。

时钟的实现分部分:

1、创建外圈path路径

2、创建刻度path路径,要区分整点,绘制时间点

3、绘制指针,(这个使用的是canvas绘制的线段,也可以使用Path,可以自己测试)

需要计算当前时针,分针,秒针的角度,然后进行绘制

整体代码:

[java] view plain copy

 print?

  1. package com.duoku.platform.demo.canvaslibrary.attract.view;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Canvas;  
  5. import android.graphics.Color;  
  6. import android.graphics.Paint;  
  7. import android.graphics.Path;  
  8. import android.graphics.PathMeasure;  
  9. import android.os.Handler;  
  10. import android.util.AttributeSet;  
  11. import android.view.View;  
  12.   
  13. import java.util.Calendar;  
  14.   
  15. /** 
  16.  * Created by chenpengfei_d on 2016/9/8. 
  17.  */  
  18. public class TimeView extends View {  
  19.     private Paint mPaint,mPaint_time;  
  20.     private Paint mPaint_h,mPaint_m,mPaint_s;  
  21.     private Path mPath_Circle;  
  22.     private Path mPath_Circle_h;  
  23.     private Path mPath_Circle_m;  
  24.     private Path mPath_h,mPath_m,mPath_s;  
  25.     private Path mPath_duration;  
  26.   
  27.     private PathMeasure mMeasure;  
  28.     private PathMeasure mMeasure_h;  
  29.     private PathMeasure mMeasure_m;  
  30.     private Handler mHandler = new Handler();  
  31.     private Runnable clockRunnable;  
  32.     private boolean isRunning;  
  33.     public TimeView(Context context) {  
  34.         super(context);  
  35.         init();  
  36.     }  
  37.   
  38.     public TimeView(Context context, AttributeSet attrs) {  
  39.         super(context, attrs);  
  40.         init();  
  41.     }  
  42.   
  43.     public TimeView(Context context, AttributeSet attrs, int defStyleAttr) {  
  44.         super(context, attrs, defStyleAttr);  
  45.         init();  
  46.     }  
  47.     int  t = 3;  
  48.     public void init(){  
  49.         //初始化画笔  
  50.         mPaint = new Paint();  
  51.         mPaint.setDither(true);  
  52.         mPaint.setAntiAlias(true);  
  53.         mPaint.setStyle(Paint.Style.STROKE);  
  54.         mPaint.setStrokeWidth(2);  
  55.         mPaint.setStrokeCap(Paint.Cap.ROUND);  
  56.         mPaint.setStrokeJoin(Paint.Join.ROUND);  
  57.         mPaint.setColor(Color.RED);  
  58.         mPaint_time = new Paint();  
  59.         mPaint_time.setDither(true);  
  60.         mPaint_time.setAntiAlias(true);  
  61.         mPaint_time.setStyle(Paint.Style.STROKE);  
  62.         mPaint_time.setStrokeWidth(2);  
  63.         mPaint_time.setTextSize(15);  
  64.         mPaint_time.setStrokeCap(Paint.Cap.ROUND);  
  65.         mPaint_time.setStrokeJoin(Paint.Join.ROUND);  
  66.         mPaint_time.setColor(Color.RED);  
  67.   
  68.         mPaint_h = new Paint();  
  69.         mPaint_h.setDither(true);  
  70.         mPaint_h.setAntiAlias(true);  
  71.         mPaint_h.setStyle(Paint.Style.STROKE);  
  72.         mPaint_h.setStrokeWidth(6);  
  73.         mPaint_h.setTextSize(15);  
  74.         mPaint_h.setStrokeCap(Paint.Cap.ROUND);  
  75.         mPaint_h.setStrokeJoin(Paint.Join.ROUND);  
  76.         mPaint_h.setColor(Color.RED);  
  77.   
  78.         mPaint_m = new Paint();  
  79.         mPaint_m.setDither(true);  
  80.         mPaint_m.setAntiAlias(true);  
  81.         mPaint_m.setStyle(Paint.Style.STROKE);  
  82.         mPaint_m.setStrokeWidth(4);  
  83.         mPaint_m.setTextSize(15);  
  84.         mPaint_m.setStrokeCap(Paint.Cap.ROUND);  
  85.         mPaint_m.setStrokeJoin(Paint.Join.ROUND);  
  86.         mPaint_m.setColor(Color.RED);  
  87.   
  88.         mPaint_s = new Paint();  
  89.         mPaint_s.setDither(true);  
  90.         mPaint_s.setAntiAlias(true);  
  91.         mPaint_s.setStyle(Paint.Style.STROKE);  
  92.         mPaint_s.setStrokeWidth(2);  
  93.         mPaint_s.setTextSize(15);  
  94.         mPaint_s.setStrokeCap(Paint.Cap.ROUND);  
  95.         mPaint_s.setStrokeJoin(Paint.Join.ROUND);  
  96.         mPaint_s.setColor(Color.RED);  
  97.         //初始化刻度  
  98.         mPath_Circle  = new Path();  
  99.         mPath_Circle.addCircle(0,0,250, Path.Direction.CCW);  
  100.         mPath_Circle_h  = new Path();  
  101.         mPath_Circle_h.addCircle(0,0,220, Path.Direction.CCW);  
  102.         mPath_Circle_m  = new Path();  
  103.         mPath_Circle_m.addCircle(0,0,235, Path.Direction.CCW);  
  104.         //初始化PathMeasure测量path坐标,  
  105.         mMeasure = new PathMeasure();  
  106.         mMeasure.setPath(mPath_Circle,true);  
  107.         mMeasure_h = new PathMeasure();  
  108.         mMeasure_h.setPath(mPath_Circle_h,true);  
  109.         mMeasure_m = new PathMeasure();  
  110.         mMeasure_m.setPath(mPath_Circle_m,true);  
  111.         //获取刻度path  
  112.         mPath_duration = new Path();  
  113.         for (int i = 60; i>0 ;i --){  
  114.             Path path = new Path();  
  115.             float pos [] = new float[2];  
  116.             float tan [] = new float[2];  
  117.             float pos2 [] = new float[2];  
  118.             float tan2 [] = new float[2];  
  119.             float pos3 [] = new float[2];  
  120.             float tan3 [] = new float[2];  
  121.             mMeasure.getPosTan(mMeasure.getLength()*i/60,pos,tan);  
  122.             mMeasure_h.getPosTan(mMeasure_h.getLength()*i/60,pos2,tan2);  
  123.             mMeasure_m.getPosTan(mMeasure_m.getLength()*i/60,pos3,tan3);  
  124.   
  125.             float x = pos[0];  
  126.             float y = pos[1];  
  127.             float x2 = pos2[0];  
  128.             float y2 = pos2[1];  
  129.             float x3 = pos3[0];  
  130.             float y3 = pos3[1];  
  131.             path.moveTo(x , y);  
  132.   
  133.             if(i% 5 ==0){  
  134.                 path.lineTo(x2,y2);  
  135.                 if(t>12){  
  136.                     t = t-12;  
  137.                 }  
  138.                 String time = t++ +"";  
  139.                 Path path_time = new Path();  
  140.                 mMeasure_h.getPosTan(mMeasure_h.getLength()*(i-1)/60,pos2,tan2);  
  141.                 mPaint.getTextPath(time,0,time.length(),(x2- (x2/15)),y2-(y2/15),path_time);  
  142.                 path.close();  
  143.                 path.addPath(path_time);  
  144.             }else{  
  145.                 path.lineTo(x3,y3);  
  146.             }  
  147.   
  148.   
  149.             mPath_duration.addPath(path);  
  150.             clockRunnable = new Runnable() {//里面做的事情就是每隔一秒,刷新一次界面  
  151.                 @Override  
  152.                 public void run() {  
  153.                     //线程中刷新界面  
  154.                     postInvalidate();  
  155.                     mHandler.postDelayed(this, 1000);  
  156.                 }  
  157.             };  
  158.         }  
  159.   
  160.         mPath_h = new Path();  
  161.         mPath_h.rLineTo(50,30);  
  162.   
  163.         mPath_m = new Path();  
  164.         mPath_m.rLineTo(80,80);  
  165.   
  166.         mPath_s = new Path();  
  167.         mPath_s.rLineTo(130,50);  
  168.     }  
  169.     private int mWidth,mHeight;  
  170.     @Override  
  171.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  172.         super.onSizeChanged(w, h, oldw, oldh);  
  173.         mWidth = w;  
  174.         mHeight = h;  
  175.     }  
  176.   
  177.     @Override  
  178.     protected void onDraw(Canvas canvas) {  
  179.         super.onDraw(canvas);  
  180.         if(!isRunning){  
  181.             isRunning = true;  
  182.             mHandler.postDelayed(clockRunnable,1000);  
  183.         }else{  
  184.             canvas.translate(mWidth/2,mHeight/2);  
  185.   
  186.             canvas.drawPath(mPath_Circle,mPaint);  
  187.             canvas.save();  
  188.             canvas.drawPath(mPath_duration,mPaint_time);  
  189.   
  190.             canvas.drawPoint(0,0,mPaint_time);  
  191.   
  192.             drawClockPoint(canvas);  
  193.         }  
  194.   
  195.   
  196.   
  197.   
  198.   
  199.     }  
  200.     private Calendar cal;  
  201.     private int hour;  
  202.     private int min;  
  203.     private int second;  
  204.     private float hourAngle,minAngle,secAngle;  
  205.     /** 
  206.      * 绘制三个指针 
  207.      * @param canvas 
  208.      */  
  209.     private void drawClockPoint(Canvas canvas) {  
  210.         cal = Calendar.getInstance();  
  211.         hour = cal.get(Calendar.HOUR);//Calendar.HOUR获取的是12小时制,Calendar.HOUR_OF_DAY获取的是24小时制  
  212.         min = cal.get(Calendar.MINUTE);  
  213.         second = cal.get(Calendar.SECOND);  
  214.         //计算时分秒指针各自需要偏移的角度  
  215.         hourAngle = (float)hour / 12 * 360 + (float)min / 60 * (360 / 12);//360/12是指每个数字之间的角度  
  216.         minAngle = (float)min / 60 * 360;  
  217.         secAngle = (float)second / 60 * 360;  
  218.         //下面将时、分、秒指针按照各自的偏移角度进行旋转,每次旋转前要先保存canvas的原始状态  
  219.         canvas.save();  
  220.         canvas.rotate(hourAngle,0, 0);  
  221.         canvas.drawLine(0, 0, mWidth/6, getHeight() / 6 - 65, mPaint_h);//时针长度设置为65  
  222.   
  223.         canvas.restore();  
  224.         canvas.save();  
  225.         canvas.rotate(minAngle,0, 0);  
  226.         canvas.drawLine(0, 0, mWidth/6, getHeight() / 6 - 90 , mPaint_m);//分针长度设置为90  
  227.   
  228.         canvas.restore();  
  229.         canvas.save();  
  230.         canvas.rotate(secAngle,0, 0);  
  231.         canvas.drawLine(0, 0, mWidth/6, getHeight() / 6 - 110 , mPaint_s);//秒针长度设置为110  
  232.   
  233.         canvas.restore();  
  234.     }  
  235. }  

这其实还不算特别复杂的动画,也许你有啥好的想法,可以自己通过Path + 属性动画来实现更好看的效果;

比如星空的效果,比如动态绘制文字 + 路径实现类似ppt中播放的一些特效,比如电子书的自动翻页。

(3)下边再介绍一个知识,就是svg:

svg是什么东西呢?

他的学名叫做可缩放矢量图形,是基于可扩展标记语言标准通用标记语言的子集),用于描述二维矢量图形的一种图形格式

这种格式的图形式可以加载到Android的Path里边。

既然可以加载到Path里边,那么是不是就可以实现更复杂的效果呢,下边看图:(明天再写了)

时间: 2024-11-03 05:07:18

Android通过Path实现复杂效果(搜索按钮+时钟的实现 )的相关文章

Android通过Path实现复杂效果(搜索按钮+时钟的实现 +svg实现)

Path : 在Android中复杂的图形的绘制绝大多数是通过path来实现,比如绘制一条曲线,然后让一个物体随着这个曲线运动,比如搜索按钮,比如一个简单时钟的实现: 那么什么是path呢! 定义:path  就是路径,就是图形的路径的集合,它里边包含了路径里边的坐标点,等等的属性.我们可以获取到任意点的坐标,正切值. 那么要获取Path上边所有点的坐标还需要用到一个类,PathMeasure; PathMesure: PathMeasure是一个用来测量Path的类,主要有以下方法: 构造方法

Android通过Path实现搜索按钮和时钟复杂效果_Android

在Android中复杂的图形的绘制绝大多数是通过path来实现,比如绘制一条曲线,然后让一个物体随着这个曲线运动,比如搜索按钮,比如一个简单时钟的实现: 那么什么是path呢!  定义:path  就是路径,就是图形的路径的集合,它里边包含了路径里边的坐标点,等等的属性.我们可以获取到任意点的坐标,正切值.  那么要获取Path上边所有点的坐标还需要用到一个类,PathMeasure;  PathMesure: PathMeasure是一个用来测量Path的类,主要有以下方法:  构造方法  

Android通过Path实现搜索按钮和时钟复杂效果

在Android中复杂的图形的绘制绝大多数是通过path来实现,比如绘制一条曲线,然后让一个物体随着这个曲线运动,比如搜索按钮,比如一个简单时钟的实现: 那么什么是path呢! 定义:path  就是路径,就是图形的路径的集合,它里边包含了路径里边的坐标点,等等的属性.我们可以获取到任意点的坐标,正切值. 那么要获取Path上边所有点的坐标还需要用到一个类,PathMeasure; PathMesure: PathMeasure是一个用来测量Path的类,主要有以下方法: 构造方法 公共方法 可

Android Button点击效果(按钮背景变色、文字变色)

一. 说明 Android Button的使用过程中,我们会需要为Button添加点击效果,不仅仅按钮的背景色需要变化,而且有时,我们连文字的颜色都希望变化,我们可以使用StateListDrawable资源可以实现. 二. 实现按钮点击的变化 2.1 实现效果: 2.2 我们首先需要定义按钮的背景的资源文件,我们使用图片资源来实现点击变化 selector_btn_click_bg.xml <?xml version="1.0" encoding="utf-8&quo

Android App中DrawerLayout抽屉效果的菜单编写实例_php技巧

抽屉效果的导航菜单看了很多应用,觉得这种侧滑的抽屉效果的菜单很好. 不用切换到另一个页面,也不用去按菜单的硬件按钮,直接在界面上一个按钮点击,菜单就滑出来,而且感觉能放很多东西. 库的引用: 首先, DrawerLayout这个类是在Support Library里的,需要加上android-support-v4.jar这个包. 然后程序中用时在前面导入import android.support.v4.widget.DrawerLayout; 如果找不到这个类,首先用SDK Manager更新

Android WaveView实现水流波动效果_Android

   水流波动的波形都是三角波,曲线是正余弦曲线,但是Android中没有提供绘制正余弦曲线的API,好在Path类有个绘制贝塞尔曲线的方法quadTo,绘制出来的是2阶的贝塞尔曲线,要想实现波动效果,只能用它来绘制Path曲线.待会儿再讲解2阶的贝塞尔曲线是怎么回事,先来看实现的效果: 这个波长比较短,还看不到起伏,只是荡漾,把波长拉长再看一下: 已经可以看到起伏很明显了,再拉长看一下: 这个的起伏感就比较强了.利用这个波动效果,可以用在绘制水位线的时候使用到,还可以做一个波动的进度条Wave

Android 使用Path实现涂鸦功能_Android

今天实现一个涂鸦效果,会分几步实现,这里有一个重要的知识点就是图层,要理解这个,不然你看这篇博客,很迷茫,迷茫的苍茫的天涯是我的爱,先从简单的需求做起,绘制一条线,代码如下: package com.tuya; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.util

Android TextView实现垂直滚动效果的方法_Android

本文实例讲述了Android TextView实现垂直滚动效果的方法.分享给大家供大家参考,具体如下: 在TextView中,如果文本很长,可能需要实现垂直滚动显示文本的效果.这里需要在XML布局文件中为TextView设置如下几个属性. Android:scrollbars="vertical" android:scrollbarStyle="X" 其中X为outsideOverlay或insideOverlay. android:scrollbarFadeDur

简单实用的Android UI微博动态点赞效果_Android

说起空间动态.微博的点赞效果,网上也是很泛滥,各种实现与效果一大堆.而详细实现的部分,讲述的也是参差不齐,另一方面估计也有很多大侠也不屑一顾,觉得完全没必要单独开篇来写和讲解吧.毕竟,也就是两个view和一些简单的动画效果罢了. 单若是只讲这些,我自然也是不愿花这番功夫的.虽然自己很菜,可也不甘于太菜.所以偶尔看到些好东西,可以延伸学写下,我还是很情愿拿出来用用,顺带秀一秀逼格什么的. 不扯太多,先说说今天实现点赞效果用到的自以为不错的两个点: Checkable 用来扩展View实现选中状态切