Android custom view implementation likes control
•
Android
This example shares the specific code of Android like control for your reference. The specific contents are as follows
Preview effect
catalogue
Image class: likeimageview text class: likechartextview integration class: likeview.java custom attribute: attrs.xml
code
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),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",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,baseline * 2);
ObjectAnimator oldAlphaAnimator = ObjectAnimator.ofFloat(this,1);
minusAnimator = new AnimatorSet();
minusAnimator.playTogether(oldYAnimator,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,attrs);
init();
}
public LikeImageView(Context context,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,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,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,shiningMoveX + selectedShiningBtimap.getWidth(),selectedShiningBtimap.getHeight());
canvas.drawBitmap(selectedShiningBtimap,shiningDst,shiningPaint);
} else {
//画灰赞
canvas.drawBitmap(unSelectedBtimap,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",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,attrs);
init();
}
public LikeView(Context 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,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 < 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);
charTvs.get(i).change(false);
chr_num++;
Logger.e("chr_num:%d,是否执行上一位动画:",(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>
The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot.
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
二维码
