首页 > 系统 > Android > 正文

Android自定义View实现点赞控件

2019-12-12 00:02:22
字体:
来源:转载
供稿:网友

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

预览效果

目录

图片类: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 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>

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表