温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Android中怎么通过自定义View实现一个点赞控件

发布时间:2021-07-29 16:00:34 来源:亿速云 阅读:129 作者:Leah 栏目:编程语言

这篇文章将为大家详细讲解有关Android中怎么通过自定义View实现一个点赞控件,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

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 MOHUFANWEI = 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) > MOHUFANWEI || Math.abs(lastY - y) > MOHUFANWEI) {     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>

关于Android中怎么通过自定义View实现一个点赞控件就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI