GuideImageView.java 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. package com.xunao.effectdemo.view;
  2. /**
  3. * author : 程中强
  4. * e-mail : 740479946@qq.com
  5. * date : 2022/8/216:51
  6. * desc :
  7. * version: 1.0
  8. */
  9. import android.content.Context;
  10. import android.graphics.Bitmap;
  11. import android.graphics.Canvas;
  12. import android.graphics.Color;
  13. import android.graphics.Paint;
  14. import android.graphics.Path;
  15. import android.graphics.PorterDuff;
  16. import android.graphics.PorterDuffXfermode;
  17. import android.graphics.RectF;
  18. import android.os.Build;
  19. import androidx.appcompat.widget.AppCompatImageView;
  20. import android.util.AttributeSet;
  21. import com.xuexiang.xui.widget.guidview.FocusShape;
  22. /**
  23. * ImageView with focus area animation
  24. *
  25. * @author xuexiang
  26. * @since 2018/11/29 上午12:48
  27. */
  28. class GuideImageView extends AppCompatImageView {
  29. private static final int DEFAULT_ANIM_COUNTER = 200;
  30. private Bitmap mBitmap;
  31. private Paint mBackgroundPaint, mErasePaint, mCircleBorderPaint;
  32. private int mBackgroundColor = Color.TRANSPARENT;
  33. private int mFocusBorderSize;
  34. private int mRoundRectRadius = 20;
  35. private Calculator mCalculator;
  36. private int mAnimCounter = 400;
  37. private int mStep = 1;
  38. private double mAnimMoveFactor = 1;
  39. private boolean mAnimationEnabled = true;
  40. private Path mPath;
  41. private RectF rectF;
  42. private int mFocusAnimationMaxValue;
  43. private int mFocusAnimationStep;
  44. private boolean isOnDraw = false;
  45. private FinishListener finishClick;
  46. public void setOnFinishListener(FinishListener finishClick){
  47. this.finishClick = finishClick;
  48. }
  49. public GuideImageView(Context context) {
  50. super(context);
  51. init();
  52. }
  53. public GuideImageView(Context context, AttributeSet attrs) {
  54. super(context, attrs);
  55. init();
  56. }
  57. public GuideImageView(Context context, AttributeSet attrs, int defStyleAttr) {
  58. super(context, attrs, defStyleAttr);
  59. init();
  60. }
  61. /**
  62. * Initializations for background and paints
  63. */
  64. private void init() {
  65. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
  66. setLayerType(LAYER_TYPE_HARDWARE, null);
  67. }
  68. setWillNotDraw(false);
  69. setBackgroundColor(Color.TRANSPARENT);
  70. mBackgroundPaint = new Paint();
  71. mBackgroundPaint.setAntiAlias(true);
  72. mBackgroundPaint.setColor(mBackgroundColor);
  73. mBackgroundPaint.setAlpha(0xFF);
  74. mErasePaint = new Paint();
  75. mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
  76. mErasePaint.setAlpha(0xFF);
  77. mErasePaint.setAntiAlias(true);
  78. mPath = new Path();
  79. mCircleBorderPaint = new Paint();
  80. mCircleBorderPaint.setAntiAlias(true);
  81. int mFocusBorderColor = Color.TRANSPARENT;
  82. mCircleBorderPaint.setColor(mFocusBorderColor);
  83. mCircleBorderPaint.setStrokeWidth(mFocusBorderSize);
  84. mCircleBorderPaint.setStyle(Paint.Style.STROKE);
  85. rectF = new RectF();
  86. }
  87. /**
  88. * Setting parameters for background an animation
  89. *
  90. * @param backgroundColor background color
  91. * @param calculator calculator object for calculations
  92. */
  93. public void setParameters(int backgroundColor, Calculator calculator) {
  94. mBackgroundColor = backgroundColor;
  95. mAnimMoveFactor = 1;
  96. mCalculator = calculator;
  97. }
  98. /**
  99. * Setting parameters for focus border
  100. *
  101. * @param focusBorderColor
  102. * @param focusBorderSize
  103. */
  104. public void setBorderParameters(int focusBorderColor, int focusBorderSize) {
  105. mFocusBorderSize = focusBorderSize;
  106. mCircleBorderPaint.setColor(focusBorderColor);
  107. mCircleBorderPaint.setStrokeWidth(focusBorderSize);
  108. }
  109. /**
  110. * Setting round rectangle radius
  111. *
  112. * @param roundRectRadius
  113. */
  114. public void setRoundRectRadius(int roundRectRadius) {
  115. mRoundRectRadius = roundRectRadius;
  116. }
  117. /**
  118. * Enable/disable animation
  119. *
  120. * @param animationEnabled
  121. */
  122. public void setAnimationEnabled(final boolean animationEnabled) {
  123. mAnimationEnabled = animationEnabled;
  124. mAnimCounter = mAnimationEnabled ? DEFAULT_ANIM_COUNTER : 0;
  125. }
  126. /**
  127. * Draws background and moving focus area
  128. *
  129. * @param canvas draw canvas
  130. */
  131. @Override
  132. protected void onDraw(Canvas canvas) {
  133. super.onDraw(canvas);
  134. if (mBitmap == null) {
  135. mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
  136. mBitmap.eraseColor(mBackgroundColor);
  137. }
  138. canvas.drawBitmap(mBitmap, 0, 0, mBackgroundPaint);
  139. if (mCalculator.hasFocus()) {
  140. if (mCalculator.getFocusShape().equals(FocusShape.CIRCLE)) {
  141. drawCircle(canvas);
  142. } else {
  143. drawRoundedRectangle(canvas);
  144. }
  145. if (mAnimationEnabled) {
  146. if (mAnimCounter == 400) {
  147. mStep = -5 * mFocusAnimationStep;
  148. } else if (mAnimCounter == 0) {
  149. // mStep = mFocusAnimationStep;
  150. mAnimationEnabled = false;
  151. }
  152. mAnimCounter = mAnimCounter + mStep;
  153. postInvalidate();
  154. }
  155. if (isOnDraw){
  156. if (mAnimCounter == 0) {
  157. mStep = 15 * mFocusAnimationStep;
  158. } else if (mAnimCounter == 600) {
  159. // mStep = mFocusAnimationStep;
  160. isOnDraw = false;
  161. if (finishClick!=null){
  162. finishClick.onFinish();
  163. }
  164. }
  165. mAnimCounter = mAnimCounter + mStep;
  166. postInvalidate();
  167. }
  168. }
  169. }
  170. /**
  171. * Draws focus circle
  172. *
  173. * @param canvas canvas to draw
  174. */
  175. private void drawCircle(Canvas canvas) {
  176. canvas.drawCircle(mCalculator.getCircleCenterX(), mCalculator.getCircleCenterY(),
  177. mCalculator.circleRadius(mAnimCounter, mAnimMoveFactor), mErasePaint);
  178. if (mFocusBorderSize > 0) {
  179. mPath.reset();
  180. mPath.moveTo(mCalculator.getCircleCenterX(), mCalculator.getCircleCenterY());
  181. mPath.addCircle(mCalculator.getCircleCenterX(), mCalculator.getCircleCenterY(),
  182. mCalculator.circleRadius(mAnimCounter, mAnimMoveFactor), Path.Direction.CW);
  183. canvas.drawPath(mPath, mCircleBorderPaint);
  184. }
  185. }
  186. /**
  187. * Draws focus rounded rectangle
  188. *
  189. * @param canvas canvas to draw
  190. */
  191. private void drawRoundedRectangle(Canvas canvas) {
  192. float left = mCalculator.roundRectLeft(mAnimCounter, mAnimMoveFactor);
  193. float top = mCalculator.roundRectTop(mAnimCounter, mAnimMoveFactor);
  194. float right = mCalculator.roundRectRight(mAnimCounter, mAnimMoveFactor);
  195. float bottom = mCalculator.roundRectBottom(mAnimCounter, mAnimMoveFactor);
  196. rectF.set(left, top, right, bottom);
  197. canvas.drawRoundRect(rectF, mRoundRectRadius, mRoundRectRadius, mErasePaint);
  198. if (mFocusBorderSize > 0) {
  199. mPath.reset();
  200. mPath.moveTo(mCalculator.getCircleCenterX(), mCalculator.getCircleCenterY());
  201. mPath.addRoundRect(rectF, mRoundRectRadius, mRoundRectRadius, Path.Direction.CW);
  202. canvas.drawPath(mPath, mCircleBorderPaint);
  203. }
  204. }
  205. public void setFocusAnimationParameters(int maxValue, int step) {
  206. mFocusAnimationMaxValue = maxValue;
  207. mFocusAnimationStep = step;
  208. }
  209. public void setDraw(){
  210. mAnimCounter = 0;
  211. isOnDraw = true;
  212. invalidate();
  213. }
  214. interface FinishListener {
  215. void onFinish();
  216. }
  217. }