Android 使用 Path 实现搜索动态加载动画效果

所属分类: 软件编程 / Android 阅读数: 49
收藏 0 赞 0 分享

今天实现一个搜索动态加载数据的动画效果,还是先看效果吧,用文字描述干巴巴的,看图说话什么都明白了,

实现这个就是使用Path中的getSegment()不断的去改变它截取片段的start和stop,再结合动画,今天就分步骤实现它,看完以后你也会觉的不是很难,只是没想到这么实现而已,所以要多见识,所谓眼界决定你的高度,还是延续我写博客的习惯,一步步分析,第一步就是绘制如下图:

如果单纯的绘制这个图很简单很简单的,绘制一个圆,然后再绘制一根线就搞定,但是要考虑这里的效果,就不能这么干了,如果你看了上面的gif图就知道,其实这是2个同心圆,然后前一个path的起点和后一个path的起点相连接就是形成一条直线了,但是path中的图形内容也就是这个圆是怎么绘制出来的呢?如果是绘制圆的话,上面的线起点和终点位置怎么去计算,这是个问题,但是我们绘制圆还可以使用绘制椭圆的形式也是可以绘制达到圆的效果,从45度开始绘制一个圆,是不是这个线的起点搞定了,分析图如下:

那么好,根据上面的分析开始写代码绘制出一个静态的搜索图:

package com.tuya;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by admin on 2016/12/17.
 */
public class DynamicSearchView2 extends View {
 private Paint paint;
 private int width;//view的宽度
 private int height;//view的高度
 private Path searchPath;
 private Path circlePath;
 private float BigCircleRectWidth;//搜索圆对应的外切正方形边长
 private PathMeasure pathMeasure;
 private float[] pos;
 public DynamicSearchView2(Context context) {
  this(context,null);
 }
 public DynamicSearchView2(Context context, AttributeSet attrs) {
  this(context, attrs,0);
 }
 public DynamicSearchView2(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init();
 }
 private void init() {
  paint = new Paint();
  paint.setAntiAlias(true);
  paint.setStrokeWidth(3);
  paint.setColor(Color.WHITE);
  paint.setStyle(Paint.Style.STROKE);
 }
 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  width = w;
  height = h;
  initPath();
 }
 /**
  * 初始化path
  */
 private void initPath() {
  searchPath = new Path();
  circlePath = new Path();
  if(width>height){//长方形
   BigCircleRectWidth = height;
  }else if(width<height){
   BigCircleRectWidth = width;
  }else{
   BigCircleRectWidth = width;
  }
  float smallbordWidth =BigCircleRectWidth/8;
  RectF searchRect = new RectF(-smallbordWidth,-smallbordWidth,smallbordWidth,smallbordWidth);
  searchPath.addArc(searchRect,45,360);
  float bigBordWidth = smallbordWidth*2;
  RectF circleRect = new RectF(-bigBordWidth,-bigBordWidth,bigBordWidth,bigBordWidth);
  circlePath.addArc(circleRect,45,-360);
  pathMeasure = new PathMeasure(circlePath,false);
  pos = new float[2];
  pathMeasure.getPosTan(0,pos,null);
  searchPath.lineTo(pos[0],pos[1]);
 }
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.translate(width/2,height/2);//平移画布把这个view的中心点当做原点
  canvas.drawPath(searchPath,paint);
  canvas.drawPath(circlePath,paint);
 }
}

效果图:

本来这个外圆是不需要draw上去的,我在这绘制上去只是告诉你这二个圆是有一定的联系,哪为什么这根线是这样的呢?我们在绘制这个圆的时候是从45度开始绘制360刚好是一周,形成了一个圆,现在做个测试不要360,就写个330度,效果如下:

这个时候你会发现这条线是对的,导致问题其实是这样的,如图分析:

把绘制椭圆的关键代码:

searchPath.addArc(searchRect,45,358);

circlePath.addArc(circleRect,45,-358);

不要写成360,改为358试试,效果图:


发现这线是不是正常了,至于外面的圆还有点缺口,第一你可以把358改成359应该没事了,还有就是我们其实真实的效果并不需要这个外面的圆,所以不改也没事,那么好,第一步算是完成了,现在想想第二步怎么实现,先把第二步的效果用gif展示看下,不然光想没思路,就像你看美女,第一眼看那,是吧,就不多说了!要有画面感,

还是画布分析:


哪我们只要改变startD这个离起始点的位置值就ok,当然有很多种方法,但是Android中基本上都是使用值动画,ok,根据这个思路实现这个第二步逻辑:

package com.tuya;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by admin on 2016/12/17.
 */
public class DynamicSearchView2 extends View {
 private Paint paint;
 private int width;//view的宽度
 private int height;//view的高度
 private Path searchPath;
 private Path circlePath;
 private float BigCircleRectWidth;//搜索圆对应的外切正方形边长
 private PathMeasure pathMeasure;
 private float[] pos;
 private float animPercent;//
 private ValueAnimator serchStartAnim;
 private long animDuration = 2000;//动画时间
 public DynamicSearchView2(Context context) {
  this(context,null);
 }
 public DynamicSearchView2(Context context, AttributeSet attrs) {
  this(context, attrs,0);
 }
 public DynamicSearchView2(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init();
 }
 private void init() {
  initPaint();
  initAnim();
  initAnimListener();
  startAnim();
 }
 /**
  * 开始执行动画
  */
 private void startAnim() {
  serchStartAnim.start();
 }
 /**
  * 动画监听
  */
 private void initAnimListener() {
  serchStartAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
   @Override
   public void onAnimationUpdate(ValueAnimator valueAnimator) {
     //获取动画在单位时间内,每次执行的值
    animPercent = (float) valueAnimator.getAnimatedValue();
    invalidate();
   }
  });
 }
 /**
  * 初始化动画
  */
 private void initAnim() {
  serchStartAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);
 }
 /**
  * 初始化画笔
  */
 private void initPaint() {
  paint = new Paint();
  paint.setAntiAlias(true);
  paint.setStrokeWidth(3);
  paint.setColor(Color.WHITE);
  paint.setStyle(Paint.Style.STROKE);
 }

 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  width = w;
  height = h;
  initPath();
 }
 /**
  * 初始化path
  */
 private void initPath() {
  searchPath = new Path();
  circlePath = new Path();
  if(width>height){//长方形
   BigCircleRectWidth = height;
  }else if(width<height){
   BigCircleRectWidth = width;
  }else{
   BigCircleRectWidth = width;
  }
  float smallbordWidth =BigCircleRectWidth/8;
  RectF searchRect = new RectF(-smallbordWidth,-smallbordWidth,smallbordWidth,smallbordWidth);

  searchPath.addArc(searchRect,45,358);
  float bigBordWidth = smallbordWidth*2;
  RectF circleRect = new RectF(-bigBordWidth,-bigBordWidth,bigBordWidth,bigBordWidth);
  circlePath.addArc(circleRect,45,-358);
  pathMeasure = new PathMeasure(circlePath,false);
  pos = new float[2];
  pathMeasure.getPosTan(0,pos,null);
  searchPath.lineTo(pos[0],pos[1]);
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
   canvas.translate(width/2,height/2);//平移画布把这个view的中心点当做原点
   drawSearch(canvas);
 }
 private void drawSearch(Canvas canvas) {
  Path dst = new Path();
  pathMeasure.setPath(searchPath,false);
  pathMeasure.getSegment(pathMeasure.getLength()*animPercent,pathMeasure.getLength(),dst,true);
  canvas.drawPath(searchPath,paint);
 }
}

效果:

现在还我们效果还差外圆的大圆的效果了,那么大圆是在小圆动画执行完毕后再去做旋转效果的,那好,我们只要监听动画就可以,画图:

package com.tuya;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by admin on 2016/12/17.
 */
public class DynamicSearchView2 extends View {
 private static final String TAG = "DynamicSearchView2";
 private Paint paint;
 private int width;//view的宽度
 private int height;//view的高度
 private Path searchPath;
 private Path circlePath;
 private float BigCircleRectWidth;//搜索圆对应的外切正方形边长
 private PathMeasure pathMeasure;
 private float[] pos;
 private float animPercent;//
 private ValueAnimator serchStartAnim;
 private ValueAnimator bigCircleAnim;//外面大圆运动的动画
 private long animDuration = 2000;//动画时间
 private int drawTag = 1;//区分是绘制搜索框还是外层圆
 public DynamicSearchView2(Context context) {
  this(context,null);
 }
 public DynamicSearchView2(Context context, AttributeSet attrs) {
  this(context, attrs,0);
 }
 public DynamicSearchView2(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init();
 }
 private void init() {
  initPaint();
  initAnim();
  initAnimListener();
  startAnim();
 }
 /**
  * 开始执行动画
  */
 private void startAnim() {
  drawTag = 1;
  serchStartAnim.start();
  invalidate();
 }
 /**
  * 开启大圆执行动画
  */
 public void startBigCirCleAnim(){
  serchStartAnim.removeAllUpdateListeners();//把上一个动画监听移除 以免总成诡异的bug
  bigCircleAnim.start();
  drawTag = 2;
 }
 /**
  * 动画监听
  */
 private void initAnimListener() {
  serchStartAnim.addListener(new Animator.AnimatorListener() {
   @Override
   public void onAnimationStart(Animator animator) {
   }
   @Override
   public void onAnimationEnd(Animator animator) {
    startBigCirCleAnim();
   }
   @Override
   public void onAnimationCancel(Animator animator) {
   }
   @Override
   public void onAnimationRepeat(Animator animator) {
   }
  });
  serchStartAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
   @Override
   public void onAnimationUpdate(ValueAnimator valueAnimator) {
    //获取动画在单位时间内,每次执行的值
    animPercent = (float) valueAnimator.getAnimatedValue();
    invalidate();
   }
  });
  bigCircleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
   @Override
   public void onAnimationUpdate(ValueAnimator valueAnimator) {
    //获取动画在单位时间内,每次执行的值
    animPercent = (float) valueAnimator.getAnimatedValue();
    invalidate();
   }
  });
 }
 /**
  * 初始化动画
  */
 private void initAnim() {
  bigCircleAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);
  serchStartAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);
 }
 /**
  * 初始化画笔
  */
 private void initPaint() {
  paint = new Paint();
  paint.setAntiAlias(true);
  paint.setStrokeWidth(3);
  paint.setColor(Color.WHITE);
  paint.setStyle(Paint.Style.STROKE);
 }
 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  width = w;
  height = h;
  initPath();
 }
 /**
  * 初始化path
  */
 private void initPath() {
  searchPath = new Path();
  circlePath = new Path();
  if(width>height){//长方形
   BigCircleRectWidth = height;
  }else if(width<height){
   BigCircleRectWidth = width;
  }else{
   BigCircleRectWidth = width;
  }
  float smallbordWidth =BigCircleRectWidth/8;
  RectF searchRect = new RectF(-smallbordWidth,-smallbordWidth,smallbordWidth,smallbordWidth);

  searchPath.addArc(searchRect,45,358);
  float bigBordWidth = smallbordWidth*2;
  RectF circleRect = new RectF(-bigBordWidth,-bigBordWidth,bigBordWidth,bigBordWidth);
  circlePath.addArc(circleRect,45,-358);
  pathMeasure = new PathMeasure(circlePath,false);
  pos = new float[2];
  pathMeasure.getPosTan(0,pos,null);
  searchPath.lineTo(pos[0],pos[1]);
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.translate(width/2,height/2);//平移画布把这个view的中心点当做原点
  drawSearch(canvas);
 }
 private void drawSearch(Canvas canvas) {
  if(drawTag==1){
   drawSearchGraph(canvas);
  }else if(drawTag==2){
   drawBigCircleGraph(canvas);
  }
 }
 /**
  * 绘制外层大圆
  * @param canvas
  */
 private void drawBigCircleGraph(Canvas canvas) {
  pathMeasure.setPath(circlePath, false);
  Path dst2 = new Path();
  float stop = pathMeasure.getLength() * animPercent;
  float start = (float) (stop - ((0.5 - Math.abs(animPercent - 0.5)) * 200f));
  pathMeasure.getSegment(start, stop, dst2, true);
  canvas.drawPath(dst2, paint);
 }
 /**
  * 绘制搜索框
  * @param canvas
  */
 private void drawSearchGraph(Canvas canvas) {
  pathMeasure.setPath(searchPath,false);
  Path dst = new Path();
  pathMeasure.getSegment(pathMeasure.getLength()*animPercent,pathMeasure.getLength(),dst,true);
  canvas.drawPath(dst,paint);
 }
}

效果:

发现转一圈就到头了,如果有特定的需求肯定是要控制整个转圈的圈数,如果是网络加载的话,除非网络特别的好,先不管了,因为等下还要写周报,也是很痛苦的

现在还差最后一步就是大圆的运动完后要绘制搜索框出来,其实这个和第一步效果刚好是相关的,

package com.tuya;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by admin on 2016/12/17.
 */
public class DynamicSearchView2 extends View {
 private static final String TAG = "DynamicSearchView2";
 private Paint paint;
 private int width;//view的宽度
 private int height;//view的高度
 private Path searchPath;
 private Path circlePath;
 private float BigCircleRectWidth;//搜索圆对应的外切正方形边长
 private PathMeasure pathMeasure;
 private float[] pos;
 private float animPercent;//
 private ValueAnimator serchStartAnim;
 private ValueAnimator bigCircleAnim;//外面大圆运动的动画
 private ValueAnimator startDrawSearchAnim;//最后一步绘制搜索框
 private long animDuration = 2000;//动画时间
 private int drawTag = 1;//区分是绘制搜索框还是外层圆
 public DynamicSearchView2(Context context) {
  this(context,null);
 }
 public DynamicSearchView2(Context context, AttributeSet attrs) {
  this(context, attrs,0);
 }
 public DynamicSearchView2(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init();
 }
 private void init() {
  initPaint();
  initAnim();
  initAnimListener();
  startAnim();
 }
 /**
  * 开始执行动画
  */
 private void startAnim() {
  drawTag = 1;
  serchStartAnim.start();
  invalidate();
 }
 /**
  * 开启大圆执行动画
  */
 public void startBigCirCleAnim(){
  serchStartAnim.removeAllUpdateListeners();//把上一个动画监听移除 以免总成诡异的bug
  bigCircleAnim.start();
  drawTag = 2;
 }
 /**
  * 最后绘制搜索框的动画
  */
 public void drawSearchAanim(){
  bigCircleAnim.removeAllUpdateListeners();//把上一个动画监听移除 以免总成诡异的bug
  startDrawSearchAnim.start();
  drawTag = 3;
 }
 /**
  * 动画监听
  */
 private void initAnimListener() {
  bigCircleAnim.addListener(new Animator.AnimatorListener() {
   @Override
   public void onAnimationStart(Animator animator) {
   }
   @Override
   public void onAnimationEnd(Animator animator) {
    drawSearchAanim();
   }
   @Override
   public void onAnimationCancel(Animator animator) {
   }
   @Override
   public void onAnimationRepeat(Animator animator) {
   }
  });
  serchStartAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
   @Override
   public void onAnimationUpdate(ValueAnimator valueAnimator) {
    //获取动画在单位时间内,每次执行的值
    animPercent = (float) valueAnimator.getAnimatedValue();
    invalidate();
   }
  });
  serchStartAnim.addListener(new Animator.AnimatorListener() {
   @Override
   public void onAnimationStart(Animator animator) {
   }
   @Override
   public void onAnimationEnd(Animator animator) {
    startBigCirCleAnim();
   }
   @Override
   public void onAnimationCancel(Animator animator) {
   }
   @Override
   public void onAnimationRepeat(Animator animator) {
   }
  });
  serchStartAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
   @Override
   public void onAnimationUpdate(ValueAnimator valueAnimator) {
    //获取动画在单位时间内,每次执行的值
    animPercent = (float) valueAnimator.getAnimatedValue();
    invalidate();
   }
  });
  bigCircleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
   @Override
   public void onAnimationUpdate(ValueAnimator valueAnimator) {
    //获取动画在单位时间内,每次执行的值
    animPercent = (float) valueAnimator.getAnimatedValue();
    invalidate();
   }
  });
  startDrawSearchAnim .addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
   @Override
   public void onAnimationUpdate(ValueAnimator valueAnimator) {
    //获取动画在单位时间内,每次执行的值
    animPercent = (float) valueAnimator.getAnimatedValue();
    invalidate();
   }
  });
 }
 /**
  * 初始化动画
  */
 private void initAnim() {
  bigCircleAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);
  serchStartAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);
  startDrawSearchAnim = ValueAnimator.ofFloat(1,0).setDuration(animDuration);
 }
 /**
  * 初始化画笔
  */
 private void initPaint() {
  paint = new Paint();
  paint.setAntiAlias(true);
  paint.setStrokeWidth(6);
  paint.setColor(Color.WHITE);
  paint.setStyle(Paint.Style.STROKE);
 }
 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  width = w;
  height = h;
  initPath();
 }
 /**
  * 初始化path
  */
 private void initPath() {
  searchPath = new Path();
  circlePath = new Path();
  if(width>height){//长方形
   BigCircleRectWidth = height;
  }else if(width<height){
   BigCircleRectWidth = width;
  }else{
   BigCircleRectWidth = width;
  }
  float smallbordWidth =BigCircleRectWidth/8;
  RectF searchRect = new RectF(-smallbordWidth,-smallbordWidth,smallbordWidth,smallbordWidth);
  searchPath.addArc(searchRect,45,358);
  float bigBordWidth = smallbordWidth*2;
  RectF circleRect = new RectF(-bigBordWidth,-bigBordWidth,bigBordWidth,bigBordWidth);
  circlePath.addArc(circleRect,45,-358);
  pathMeasure = new PathMeasure(circlePath,false);
  pos = new float[2];
  pathMeasure.getPosTan(0,pos,null);
  searchPath.lineTo(pos[0],pos[1]);
 }
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.translate(width/2,height/2);//平移画布把这个view的中心点当做原点
  drawSearch(canvas);
 }
 private void drawSearch(Canvas canvas) {
  if(drawTag==1){
   drawSearchGraph(canvas);
  }else if(drawTag==2){
   drawBigCircleGraph(canvas);
  }else if(drawTag==3){
   drawSearchBox(canvas);
  }
 }
 /**
  * 最后一步绘制搜索框 从终点到起点
  * @param canvas
  */
 private void drawSearchBox(Canvas canvas) {
  pathMeasure.setPath(searchPath, false);
  Path dst3 = new Path();
  pathMeasure.getSegment(pathMeasure.getLength() * animPercent, pathMeasure.getLength(), dst3, true);
  canvas.drawPath(dst3, paint);
 }
 /**
  * 绘制外层大圆
  * @param canvas
  */
 private void drawBigCircleGraph(Canvas canvas) {
  pathMeasure.setPath(circlePath, false);
  Path dst2 = new Path();
  float stop = pathMeasure.getLength() * animPercent;
  float start = (float) (stop - ((0.5 - Math.abs(animPercent - 0.5)) * 200f));
  pathMeasure.getSegment(start, stop, dst2, true);
  canvas.drawPath(dst2, paint);
 }
 /**
  * 绘制搜索框
  * @param canvas
  */
 private void drawSearchGraph(Canvas canvas) {
  pathMeasure.setPath(searchPath,false);
  Path dst = new Path();
  pathMeasure.getSegment(pathMeasure.getLength()*animPercent,pathMeasure.getLength(),dst,true);
  canvas.drawPath(dst,paint);
 }
}

效果:

github: https://github.com/zhouguizhi/PathSearch

以上所述是小编给大家介绍的Android 使用 Path 实现搜索动态加载动画效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

更多精彩内容其他人还在看

使用ViewPager实现android软件使用向导功能实现步骤

现在的大部分android软件,都是使用说明,就是第一次使用该软件时,会出现向导,可以左右滑动,然后就进入应用的主界面了,下面我们就实现这个功能
收藏 0 赞 0 分享

android在异步任务中关闭Cursor的代码方法

android在异步任务中如何关闭Cursor?在我们开发应用的时候,很多时候会遇到这种问题,下面我们就看看代码如何实现
收藏 0 赞 0 分享

Android自定义桌面功能代码实现

android自定义桌面其实很简单,看一个例子就明白了
收藏 0 赞 0 分享

android将图片转换存到数据库再从数据库读取转换成图片实现代码

有时候我们想把图片存入到数据库中,尽管这不是一种明智的选择,但有时候还是不得以会用到,下面说说将图片转换成byte[]数组存入到数据库中去,并从数据库中取出来转换成图像显示出来
收藏 0 赞 0 分享

TextView显示系统时间(时钟功能带秒针变化

用System.currentTimeMillis()可以获取系统当前的时间,我们可以开启一个线程,然后通过handler发消息,来实时的更新TextView上显示的系统时间,可以做一个时钟的功能
收藏 0 赞 0 分享

Android用ListView显示SDCard文件列表的小例子

本文简单实现了用ListView显示SDCard文件列表,目录的回退等功能暂不讨论,获取文件列表,files即为所选择目录下的所有文件列表
收藏 0 赞 0 分享

Android拦截外拨电话程序示例

这篇文章主要介绍了Android拦截外拨电话的示例,大家参考使用吧
收藏 0 赞 0 分享

通过Html网页调用本地安卓(android)app程序代码

如何使用html网页和本地app进行传递数据呢?经过研究,发现还是有方法的,总结了一下,大致有一下几种方式
收藏 0 赞 0 分享

android Textview文字监控(Textview使用方法)

以手机号充值为例,当用户输入最后一位数时候,进行汇率的变换,本文就实现类似这样的功能
收藏 0 赞 0 分享

Android ListView长按弹出菜单二种实现方式示例

这篇文章主要介绍了Android ListView长按弹出菜单的方法,大家参考实现
收藏 0 赞 0 分享
查看更多