前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android自定义View实现点赞控件

Android自定义View实现点赞控件

作者头像
砸漏
发布2020-10-16 11:47:47
4040
发布2020-10-16 11:47:47
举报
文章被收录于专栏:恩蓝脚本恩蓝脚本

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

预览效果

目录

图片类:LikeImageView 文字类:LikeCharTextView 整合类:LikeView.java 自定义属性:attrs.xml

代码

LikeCharTextView

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
<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 

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-09-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档