欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义View实现点赞控件

程序员文章站 2022-05-31 12:44:46
本文实例为大家分享了android点赞控件的具体代码,供大家参考,具体内容如下 预览效果 目录 图片类:likeimageview 文字类:likechartextview...

本文实例为大家分享了android点赞控件的具体代码,供大家参考,具体内容如下

预览效果

Android自定义View实现点赞控件

目录

图片类:likeimageview
文字类:likechartextview
整合类:likeview.java
自定义属性:attrs.xml

代码

likechartextview

public class likechartextview extends view {

 public static final int default_textcolor = color.black;
 public static final int default_textsize = 36;

 private textpaint newtextpaint, oldtextpaint;

 private animatorset addanimator;
 private animatorset minusanimator;

 private int  measurewidth;
 private int  measureheight;

 private int  textcolor  = default_textcolor;
 private int  textsize  = default_textsize;

 private int  num;
 private int  oldnum;
 private int  newnum;

 private int  animatoroldy;
 private float  animatoroldalpha = 1;

 private int  animatornewy;
 private float  animatornewalpha = 0;
 private int  baseline;

 public likechartextview(context context) {
 super(context);

 init();
 }

 public likechartextview(context context, @nullable attributeset attrs) {
 super(context, attrs);

 initattr(context, attrs);

 init();
 }

 public likechartextview(context context, @nullable attributeset attrs,
    int defstyleattr) {
 super(context, attrs, defstyleattr);

 initattr(context, attrs);

 init();
 }

 /**
 * 初始化属性
 *
 * @param context
 * @param attrs
 */
 private void initattr(context context, @nullable attributeset attrs) {
 typedarray typedarray = context.obtainstyledattributes(attrs,
  r.styleable.likechartextview);
 textcolor = typedarray.getcolor(r.styleable.likechartextview_textcolor,
  default_textcolor);
 textsize = typedarray.getdimensionpixelsize(r.styleable.likechartextview_textsize,
  default_textsize);
 num = typedarray.getint(r.styleable.likechartextview_number, 0);
 if (0 > num || num > 10) {
  throw new illegalargumentexception("number is only 0-9");
 }
 oldnum = num;

 typedarray.recycle();
 }

 /**
 * 初始化
 */
 private void init() {
 initpaints();
 initparams();
 }

 /**
 * 初始化画笔
 */
 private void initpaints() {
 newtextpaint = new textpaint(paint.anti_alias_flag);
 newtextpaint.setstyle(paint.style.fill);
 newtextpaint.settextsize(textsize);
 newtextpaint.setcolor(textcolor);
 newtextpaint.settextalign(paint.align.center);

 oldtextpaint = new textpaint(paint.anti_alias_flag);
 oldtextpaint.set(newtextpaint);
 }

 /**
 * 初始化参数
 */
 private void initparams() {
 paint.fontmetrics fontmetrics = newtextpaint.getfontmetrics();
 measurewidth = (int) newtextpaint.measuretext(string.valueof(num));
 measureheight = (int) (fontmetrics.bottom - fontmetrics.top);

 float distance = (fontmetrics.bottom - fontmetrics.top) / 2 - fontmetrics.bottom;
 baseline = (int) (measureheight * 1.0f / 2 + distance);

 animatoroldy = baseline;
 }

 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
 super.onmeasure(widthmeasurespec, heightmeasurespec);

 int widthmode = measurespec.getmode(widthmeasurespec);
 int widthsize = measurespec.getsize(widthmeasurespec);
 switch (widthmode) {
  case measurespec.unspecified:
  break;
  case measurespec.at_most:
  widthsize = measurewidth;
  break;
  case measurespec.exactly:
  break;
 }

 int heightmode = measurespec.getmode(widthmeasurespec);
 int heightsize = measurespec.getsize(widthmeasurespec);
 switch (heightmode) {
  case measurespec.unspecified:
  break;
  case measurespec.at_most:
  heightsize = measureheight;
  break;
  case measurespec.exactly:
  break;
 }

 setmeasureddimension(widthsize, heightsize);
 }

 @override
 protected void ondraw(canvas canvas) {
 super.ondraw(canvas);
 int width = getwidth();
 int height = getheight();
 oldtextpaint.setalpha((int) (255 * animatoroldalpha));
 canvas.drawtext(string.valueof(oldnum), width / 2, animatoroldy, oldtextpaint);

 newtextpaint.setalpha((int) (255 * animatornewalpha));
 canvas.drawtext(string.valueof(newnum), width / 2, animatornewy, newtextpaint);
 }

 public void settextcolor(int textcolor) {
 this.textcolor = textcolor;
 init();
 invalidate();
 }

 public void settextsize(int textsize) {
 this.textsize = textsize;
 init();
 invalidate();
 }

 public void setanimatoroldy(int animatoroldy) {
 this.animatoroldy = animatoroldy;
 invalidate();
 }

 public void setanimatoroldalpha(float animatoroldalpha) {
 this.animatoroldalpha = animatoroldalpha;
 invalidate();
 }

 public void setanimatornewy(int animatornewy) {
 this.animatornewy = animatornewy;
 invalidate();
 }

 public void setanimatornewalpha(float animatornewalpha) {
 this.animatornewalpha = animatornewalpha;
 invalidate();
 }

 public void setnum(int num) {
 this.num = num;
 if (0 > num || num > 10) {
  throw new illegalargumentexception("number is only 0-9");
 }
 oldnum = num;
 invalidate();
 }

 public void add() {
 logger.e("执行加动画.基线:" + baseline);
 objectanimator oldyanimator = objectanimator.ofint(this, "animatoroldy", baseline, 0);
 objectanimator oldalphaanimator = objectanimator.offloat(this, "animatoroldalpha", 1, 0);
 objectanimator newyanimator = objectanimator.ofint(this, "animatornewy", baseline * 2,
  baseline);
 objectanimator newalphaanimator = objectanimator.offloat(this, "animatornewalpha", 0, 1);

 addanimator = new animatorset();
 addanimator.playtogether(oldyanimator, oldalphaanimator, newyanimator, newalphaanimator);
 addanimator.setinterpolator(new linearinterpolator());
 addanimator.setduration(300);
 addanimator.start();
 }

 public void minus() {
 logger.e("执行减动画.基线:" + baseline);
 objectanimator oldyanimator = objectanimator.ofint(this, "animatoroldy", baseline,
  baseline * 2);
 objectanimator oldalphaanimator = objectanimator.offloat(this, "animatoroldalpha", 1, 0);
 objectanimator newyanimator = objectanimator.ofint(this, "animatornewy", 0, baseline);
 objectanimator newalphaanimator = objectanimator.offloat(this, "animatornewalpha", 0, 1);

 minusanimator = new animatorset();
 minusanimator.playtogether(oldyanimator, oldalphaanimator, newyanimator, newalphaanimator);
 minusanimator.setinterpolator(new linearinterpolator());
 minusanimator.setduration(300);
 minusanimator.start();
 }

 public void change(boolean isadd) {
 logger.e("chartextvie.点击事件:" + isadd);
 if (isadd) {
  if (null != addanimator && addanimator.isstarted()) {
  logger.e("chartextvie.加动画已执行.取消");
  addanimator.cancel();
  }
  if (null != minusanimator && minusanimator.isstarted()) {
  logger.e("chartextvie.减动画已执行.取消");
  minusanimator.cancel();
  }
  sumnum(false);
  minus();
 } else {
  if (null != minusanimator && minusanimator.isstarted()) {
  logger.e("chartextvie.减动画已执行.取消");
  minusanimator.cancel();
  }
  if (null != addanimator && addanimator.isstarted()) {
  logger.e("chartextvie.加动画已执行.取消");
  addanimator.cancel();
  }
  sumnum(true);
  add();
 }
 }

 /**
 * 重新计算绘画的值
 *
 * @param isadd
 */
 private void sumnum(boolean isadd) {
 logger.e("计算值开始");
 oldnum = num;
 newnum = num + (isadd ? 1 : -1);
 if (newnum < 0) {
  newnum = 9;
 } else if (newnum > 9) {
  newnum = 0;
 }
 num = newnum;
 logger.e("计算值结束:" + num);
 }
}

likeimageview

public class likeimageview extends view {

 private paint imagepaint, shiningpaint;

 private int shiningmovex;
 private int shiningmovey;

 private int measurewidth;
 private int measureheight;
 private bitmap selectedbtimap;
 private bitmap selectedshiningbtimap;
 private bitmap unselectedbtimap;

 private boolean isadd = false;

 private float shiningalpha = isadd ? 1f : 0f;

 public likeimageview(context context) {
 super(context);

 init();
 }

 public likeimageview(context context, @nullable attributeset attrs) {
 super(context, attrs);

 init();
 }

 public likeimageview(context context, @nullable attributeset attrs, int defstyleattr) {
 super(context, attrs, defstyleattr);

 init();
 }

 private void init() {
 imagepaint = new paint(paint.anti_alias_flag);
 shiningpaint = new paint(paint.anti_alias_flag);

 selectedbtimap = bitmapfactory.decoderesource(getresources(), r.mipmap.ic_like_selected);
 selectedshiningbtimap = bitmapfactory.decoderesource(getresources(),
  r.mipmap.ic_like_selected_shining);
 unselectedbtimap = bitmapfactory.decoderesource(getresources(),
  r.mipmap.ic_like_unselected);
 }

 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
 super.onmeasure(widthmeasurespec, heightmeasurespec);

 int widthmode = measurespec.getmode(widthmeasurespec);
 int widthsize = measurespec.getsize(widthmeasurespec);
 switch (widthmode) {
  case measurespec.unspecified:
  break;
  case measurespec.at_most:
  widthsize = math.max(selectedbtimap.getwidth(), unselectedbtimap.getwidth());
  shiningmovex = (int) (widthsize * 1.0f - selectedshiningbtimap.getwidth()) - 2;
  break;
  case measurespec.exactly:
  break;
 }

 int heightmode = measurespec.getmode(widthmeasurespec);
 int heightsize = measurespec.getsize(widthmeasurespec);
 switch (heightmode) {
  case measurespec.unspecified:
  break;
  case measurespec.at_most:
  heightsize = math.max(selectedbtimap.getheight(), unselectedbtimap.getheight());
  shiningmovey = (int) (selectedshiningbtimap.getheight() * 1.0f / 3);
  heightsize += shiningmovey;
  break;
  case measurespec.exactly:
  break;
 }

 setmeasureddimension(widthsize, heightsize);
 }

 @override
 protected void ondraw(canvas canvas) {
 super.ondraw(canvas);

 int width = getwidth();
 int height = getheight();
 rect src = new rect(0, 0, width, height);
 rect selectdst = new rect(0, shiningmovey, selectedbtimap.getwidth(), height);
 if (isadd) {
  //画红赞
  canvas.drawbitmap(selectedbtimap, src, selectdst, imagepaint);
  //画阴影
  shiningpaint.setalpha((int) (255 * shiningalpha));
  rect shiningdst = new rect(shiningmovex, 0,
   shiningmovex + selectedshiningbtimap.getwidth(), selectedshiningbtimap.getheight());
  canvas.drawbitmap(selectedshiningbtimap, src, shiningdst, shiningpaint);
 } else {
  //画灰赞
  canvas.drawbitmap(unselectedbtimap, src, selectdst, imagepaint);
 }
 }

 public void setshiningalpha(float shiningalpha) {
 this.shiningalpha = shiningalpha;
 invalidate();
 }

 public void setadd(boolean add) {
 isadd = add;
 shiningalpha = 1.0f;
 invalidate();
 }

 public void changelike(boolean isadd) {
 this.isadd = !isadd;
 invalidate();
 anim();
 }

 private void anim() {
 objectanimator scalexanim = objectanimator.offloat(this, "scalex", 0.7f, 1f);
 scalexanim.setduration(500);
 objectanimator scaleyanim = objectanimator.offloat(this, "scaley", 0.7f, 1f);
 scaleyanim.setduration(500);
 objectanimator alphaanim = objectanimator.offloat(this, "shiningalpha", 0f, 1f);
 alphaanim.setduration(500);
 animatorset animatorset = new animatorset();
 animatorset.playtogether(scalexanim, scaleyanim, alphaanim);
 animatorset.setinterpolator(new bounceinterpolator());
 animatorset.start();
 }
}

likeview

public class likeview extends linearlayout {
 private final int imagepadding = 4;

 private boolean isadd = false;

 private int num;
 private int textsize;
 private int textcolor;

 private int imagepadding;

 private list<likechartextview> chartvs = new arraylist<>();
 private likeimageview likeimageview;

 public likeview(context context) {
 super(context);
 init();
 }

 public likeview(context context, @nullable attributeset attrs) {
 super(context, attrs);

 initattr(context, attrs);

 init();
 }

 public likeview(context context, @nullable attributeset attrs, int defstyleattr) {
 super(context, attrs, defstyleattr);

 initattr(context, attrs);

 init();
 }

 private void initattr(context context, attributeset attrs) {
 typedarray typedarray = context.obtainstyledattributes(attrs, r.styleable.likeview);
 textcolor = typedarray.getcolor(r.styleable.likeview_textcolor,
  likechartextview.default_textcolor);
 textsize = typedarray.getdimensionpixelsize(r.styleable.likeview_textsize,
  likechartextview.default_textsize);
 num = typedarray.getint(r.styleable.likeview_number, 0);
 imagepadding = typedarray.getdimensionpixelsize(r.styleable.likeview_imagepadding, imagepadding);

 typedarray.recycle();
 }

 /**
 * 初始化
 */
 private void init() {

 initview();
 }

 protected void initview() {
 removeallviews();

 likeimageview = new likeimageview(getcontext());
 likeimageview.setadd(isadd);
 linearlayout.layoutparams layoutparams = new linearlayout.layoutparams(viewgroup.layoutparams.wrap_content, viewgroup.layoutparams.wrap_content);
 layoutparams.rightmargin = imagepadding;
 likeimageview.setlayoutparams(layoutparams);
 addview(likeimageview);

 chartvs.clear();
 string str_num = string.valueof(num);
 for (int i = 0; i < str_num.length(); i++) {
  likechartextview textview = new likechartextview(getcontext());
  int show_num = integer.valueof(str_num.substring(i, i + 1));
  log.e("zanview", "show_num:" + show_num);
  textview.settextsize(textsize);
  textview.settextcolor(textcolor);
  textview.setnum(show_num);
  addview(textview);
  chartvs.add(textview);
 }
 }

 public void setnum(int num) {
 this.num = num;
 init();
 invalidate();
 }

 public void setadd(boolean add) {
 isadd = add;
 }

 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
 super.onmeasure(widthmeasurespec, heightmeasurespec);
 //计算出所有的childview的宽高
 measurechildren(widthmeasurespec, heightmeasurespec);
 setmeasureddimension(measurewidth(widthmeasurespec), measureheight(heightmeasurespec));
 }

 /**
 * 测量宽度
 *
 * @param widthmeasurespec
 * @return
 */
 private int measurewidth(int widthmeasurespec) {
 int widthmode = measurespec.getmode(widthmeasurespec);
 int widthsize = measurespec.getsize(widthmeasurespec);
 switch (widthmode) {
  case measurespec.unspecified:
  break;
  case measurespec.at_most:
  widthsize = 0;
  for (int i = 0; i < getchildcount(); i++) {
   view childview = getchildat(i);
   //获取子view的宽
   int cwidth = childview.getmeasuredwidth();
   marginlayoutparams params = (marginlayoutparams) childview.getlayoutparams();
   widthsize += cwidth + params.leftmargin + params.rightmargin;
  }
  break;
  case measurespec.exactly:
  break;
 }
 return widthsize;
 }

 /**
 * 测量高度
 *
 * @param widthmeasurespec
 * @return
 */
 private int measureheight(int widthmeasurespec) {
 int heightmode = measurespec.getmode(widthmeasurespec);
 int heightsize = measurespec.getsize(widthmeasurespec);
 switch (heightmode) {
  case measurespec.unspecified:
  break;
  case measurespec.at_most:
  heightsize = 0;
  for (int i = 0; i < getchildcount(); i++) {
   view childview = getchildat(i);
   //获取子view的宽
   int cwidth = childview.getmeasuredheight();
   marginlayoutparams params = (marginlayoutparams) childview.getlayoutparams();
   int height = cwidth + params.leftmargin + params.rightmargin;
   heightsize = math.max(heightsize, height);
  }
  break;
  case measurespec.exactly:
  break;
 }
 return heightsize;
 }

 private boolean click = false;

 private final int *fanwei = 10;

 private float lastx = 0;
 private float lasty = 0;

 @override
 public boolean ontouchevent(motionevent event) {
 super.ontouchevent(event);
 float x = event.getx();
 float y = event.gety();

 switch (event.getaction()) {
  case motionevent.action_down:
  if (1 == event.getpointercount()) {
   click = true;
  }
  break;
  case motionevent.action_up:
  if (click) {
   onclick();
  }
  break;
  case motionevent.action_move:
  if (math.abs(lastx - x) > *fanwei || math.abs(lasty - y) > *fanwei) {
   click = false;
  }
  break;
 }

 lastx = x;
 lasty = y;
 return true;
 }

 private void onclick() {
 logger.e("点击事件" + isadd);
 string str_num = string.valueof(num);
 logger.e("点击事件,str_num:" + str_num);
 boolean nextanim = false;
 if (isadd) {
  likeimageview.changelike(true);
  for (int i = (str_num.length() - 1); i >= 0; i--) {
  int chr_num = integer.valueof(str_num.substring(i, i + 1));
  logger.e("点击事件,chr_num:%d,chartvs.size:%d,i:%d", chr_num, chartvs.size(), i);
  logger.e("是否执行动画:" + (chartvs.size() > i));
  if (chartvs.size() > i) {
   if (i == (str_num.length() - 1) || nextanim) {
   logger.e("点击事件,执行个位动画||%b执行执行上%d位动画", nextanim, i);
   chartvs.get(i).change(true);

   chr_num--;
   logger.e("chr_num:%d,是否执行上一位动画:", chr_num, (chr_num < 0));
   if (chr_num < 0) {
    nextanim = true;
   } else {
    nextanim = false;
   }

   logger.e("nextanim:" + nextanim);
   }
  }
  }
  num--;
  isadd = !isadd;
 } else {
  likeimageview.changelike(false);
  for (int i = (str_num.length() - 1); i >= 0; i--) {
  int chr_num = integer.valueof(str_num.substring(i, i + 1));
  logger.e("点击事件,chr_num:%d,chartvs.size:%d,i:%d", chr_num, chartvs.size(), i);
  logger.e("是否执行动画:" + (chartvs.size() > i));
  if (chartvs.size() > i) {
   if (i == (str_num.length() - 1) || nextanim) {
   logger.e("点击事件,执行个位动画||%b执行执行上%d位动画", nextanim, i);
   chartvs.get(i).change(false);

   chr_num++;
   logger.e("chr_num:%d,是否执行上一位动画:", chr_num, (chr_num > 9));
   if (chr_num > 9) {
    nextanim = true;
   } else {
    nextanim = false;
   }
   logger.e("nextanim:" + nextanim);
   }
  }
  }
  num++;
  isadd = !isadd;
 }
 }
}

attrs.xml

<attr name="textsize" format="dimension" />
 <attr name="textcolor" format="color" />
 <attr name="number" format="integer" />

 <attr name="imagewidth" format="dimension" />
 <attr name="imageheight" format="dimension" />

 <declare-styleable name="likeview">
 <attr name="textsize" />
 <attr name="textcolor" />
 <attr name="number" />
 <attr name="imagewithd" />
 <attr name="imageheight" />
 <attr name="imagepadding" format="dimension" />
 </declare-styleable>

 <declare-styleable name="likechartextview">
 <attr name="textsize" />
 <attr name="textcolor" />
 <attr name="number" />
 </declare-styleable>

 <declare-styleable name="likeimageview">
 <attr name="imagewithd" />
 <attr name="imageheight" />
</declare-styleable>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。