1. 程式人生 > 程式設計 >Android自定義View實現點贊控制元件

Android自定義View實現點贊控制元件

本文例項為大家分享了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),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>

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。