zoukankan      html  css  js  c++  java
  • 11.粘性控件

    粘性控件 (对View的自定义)
    应用场景: 未读提醒的清除
    功能实现:
    > 1. 画静态图 OK
    > 2. 把静态的数值变成变量(计算得到真实的变量) OK 
    > 3. 不断地修改变量, 重绘界面, 动起来了.
    > 4. 功能分析:
        a. 拖拽超出范围,断开, 松手, 消失
        b. 拖拽超出范围,断开,放回去了,恢复
        c. 拖拽没超出范围, 松手,弹回去
    240px-Bezier_2_big.gif240px-Bezier_3_big.gif

    没有布局:
    MainActivity
    1. public class MainActivity extends Activity {
    2. @Override
    3. protected void onCreate(Bundle savedInstanceState) {
    4. super.onCreate(savedInstanceState);
    5. requestWindowFeature(Window.FEATURE_NO_TITLE);
    6. setContentView(new GooView(MainActivity.this));
    7. }
    8. }
    Utils
    1. public class Utils {
    2. public static Toast mToast;
    3. public static void showToast(Context mContext, String msg) {
    4. if (mToast == null) {
    5. mToast = Toast.makeText(mContext, "", Toast.LENGTH_SHORT);
    6. }
    7. mToast.setText(msg);
    8. mToast.show();
    9. }
    10. /**
    11. * dip 转换成 px
    12. * @param dip
    13. * @param context
    14. * @return
    15. */
    16. public static float dip2Dimension(float dip, Context context) {
    17. DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
    18. return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
    19. }
    20. /**
    21. * @param dip
    22. * @param context
    23. * @param complexUnit {@link TypedValue#COMPLEX_UNIT_DIP} {@link TypedValue#COMPLEX_UNIT_SP}}
    24. * @return
    25. */
    26. public static float toDimension(float dip, Context context, int complexUnit) {
    27. DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
    28. return TypedValue.applyDimension(complexUnit, dip, displayMetrics);
    29. }
    30. /** 获取状态栏高度
    31. * @param v
    32. * @return
    33. */
    34. public static int getStatusBarHeight(View v) {
    35. if (v == null) {
    36. return 0;
    37. }
    38. Rect frame = new Rect();
    39. v.getWindowVisibleDisplayFrame(frame);
    40. return frame.top;
    41. }
    42. public static String getActionName(MotionEvent event) {
    43. String action = "unknow";
    44. switch (MotionEventCompat.getActionMasked(event)) {
    45. case MotionEvent.ACTION_DOWN:
    46. action = "ACTION_DOWN";
    47. break;
    48. case MotionEvent.ACTION_MOVE:
    49. action = "ACTION_MOVE";
    50. break;
    51. case MotionEvent.ACTION_UP:
    52. action = "ACTION_UP";
    53. break;
    54. case MotionEvent.ACTION_CANCEL:
    55. action = "ACTION_CANCEL";
    56. break;
    57. case MotionEvent.ACTION_SCROLL:
    58. action = "ACTION_SCROLL";
    59. break;
    60. case MotionEvent.ACTION_OUTSIDE:
    61. action = "ACTION_SCROLL";
    62. break;
    63. default:
    64. break;
    65. }
    66. return action;
    67. }
    68. }
    GooView
    1. /**
    2. * 粘性控件
    3. * @author poplar
    4. *
    5. */
    6. public class GooView extends View {
    7. private static final String TAG = "TAG";
    8. private Paint mPaint;
    9. public GooView(Context context) {
    10. this(context, null);
    11. }
    12. public GooView(Context context, AttributeSet attrs) {
    13. this(context, attrs , 0);
    14. }
    15. public GooView(Context context, AttributeSet attrs, int defStyle) {
    16. super(context, attrs, defStyle);
    17. // 做初始化操作
    18. mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    19. mPaint.setColor(Color.RED);
    20. }
    21. PointF[] mStickPoints = new PointF[]{
    22. new PointF(250f, 250f),
    23. new PointF(250f, 350f)
    24. };
    25. PointF[] mDragPoints = new PointF[]{
    26. new PointF(50f, 250f),
    27. new PointF(50f, 350f)
    28. };
    29. PointF mControlPoint = new PointF(150f, 300f);
    30. PointF mDragCenter = new PointF(80f, 80f);
    31. float mDragRadius = 14f;
    32. PointF mStickCenter = new PointF(150f, 150f);
    33. float mStickRadius = 12f;
    34. private int statusBarHeight;
    35. float farestDistance = 80f;
    36. private boolean isOutofRange;
    37. private boolean isDisappear;
    38. @Override
    39. protected void onDraw(Canvas canvas) {
    40. // 计算连接点值, 控制点, 固定圆半径
    41. // 1. 获取固定圆半径(根据两圆圆心距离)
    42. float tempStickRadius = getTempStickRadius();
    43. // 2. 获取直线与圆的交点
    44. float yOffset = mStickCenter.y - mDragCenter.y;
    45. float xOffset = mStickCenter.x - mDragCenter.x;
    46. Double lineK = null;
    47. if(xOffset != 0){
    48. lineK = (double) (yOffset / xOffset);
    49. }
    50. // 通过几何图形工具获取交点坐标
    51. mDragPoints = GeometryUtil.getIntersectionPoints(mDragCenter, mDragRadius, lineK);
    52. mStickPoints = GeometryUtil.getIntersectionPoints(mStickCenter, tempStickRadius, lineK);
    53. // 3. 获取控制点坐标
    54. mControlPoint = GeometryUtil.getMiddlePoint(mDragCenter, mStickCenter);
    55. // 保存画布状态
    56. canvas.save();
    57. canvas.translate(0, -statusBarHeight);
    58. // 画出最大范围(参考用)
    59. mPaint.setStyle(Style.STROKE);
    60. canvas.drawCircle(mStickCenter.x, mStickCenter.y, farestDistance, mPaint);
    61. mPaint.setStyle(Style.FILL);
    62. if(!isDisappear){
    63. if(!isOutofRange){
    64. // 3. 画连接部分
    65. Path path = new Path();
    66. // 跳到点1
    67. path.moveTo(mStickPoints[0].x, mStickPoints[0].y);
    68. // 画曲线1 -> 2
    69. path.quadTo(mControlPoint.x, mControlPoint.y, mDragPoints[0].x, mDragPoints[0].y);
    70. // 画直线2 -> 3
    71. path.lineTo(mDragPoints[1].x, mDragPoints[1].y);
    72. // 画曲线3 -> 4
    73. path.quadTo(mControlPoint.x, mControlPoint.y, mStickPoints[1].x, mStickPoints[1].y);
    74. path.close();
    75. canvas.drawPath(path, mPaint);
    76. // 画附着点(参考用)
    77. mPaint.setColor(Color.BLUE);
    78. canvas.drawCircle(mDragPoints[0].x, mDragPoints[0].y, 3f, mPaint);
    79. canvas.drawCircle(mDragPoints[1].x, mDragPoints[1].y, 3f, mPaint);
    80. canvas.drawCircle(mStickPoints[0].x, mStickPoints[0].y, 3f, mPaint);
    81. canvas.drawCircle(mStickPoints[1].x, mStickPoints[1].y, 3f, mPaint);
    82. mPaint.setColor(Color.RED);
    83. // 2. 画固定圆
    84. canvas.drawCircle(mStickCenter.x, mStickCenter.y, tempStickRadius, mPaint);
    85. }
    86. // 1. 画拖拽圆
    87. canvas.drawCircle(mDragCenter.x, mDragCenter.y, mDragRadius, mPaint);
    88. }
    89. // 恢复上次的保存状态
    90. canvas.restore();
    91. }
    92. // 获取固定圆半径(根据两圆圆心距离)
    93. private float getTempStickRadius() {
    94. float distance = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter);
    95. // if(distance> farestDistance){
    96. // distance = farestDistance;
    97. // }
    98. distance = Math.min(distance, farestDistance);
    99. // 0.0f -> 1.0f
    100. float percent = distance / farestDistance;
    101. Log.d(TAG, "percent: " + percent);
    102. // percent , 100% -> 20%
    103. return evaluate(percent, mStickRadius, mStickRadius * 0.2f);
    104. }
    105. public Float evaluate(float fraction, Number startValue, Number endValue) {
    106. float startFloat = startValue.floatValue();
    107. return startFloat + fraction * (endValue.floatValue() - startFloat);
    108. }
    109. @Override
    110. public boolean onTouchEvent(MotionEvent event) {
    111. float x;
    112. float y;
    113. switch (event.getAction()) {
    114. case MotionEvent.ACTION_DOWN:
    115. isOutofRange = false;
    116. isDisappear = false;
    117. x = event.getRawX();
    118. y = event.getRawY();
    119. updateDragCenter(x, y);
    120. break;
    121. case MotionEvent.ACTION_MOVE:
    122. x = event.getRawX();
    123. y = event.getRawY();
    124. updateDragCenter(x, y);
    125. // 处理断开事件
    126. float distance = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter);
    127. if(distance > farestDistance){
    128. isOutofRange = true;
    129. invalidate();
    130. }
    131. break;
    132. case MotionEvent.ACTION_UP:
    133. if(isOutofRange){
    134. float d = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter);
    135. if(d > farestDistance){
    136. // a. 拖拽超出范围,断开, 松手, 消失
    137. isDisappear = true;
    138. invalidate();
    139. }else {
    140. //b. 拖拽超出范围,断开,放回去了,恢复
    141. updateDragCenter(mStickCenter.x, mStickCenter.y);
    142. }
    143. }else {
    144. // c. 拖拽没超出范围, 松手,弹回去
    145. final PointF tempDragCenter = new PointF(mDragCenter.x, mDragCenter.y);
    146. ValueAnimator mAnim = ValueAnimator.ofFloat(1.0f);
    147. mAnim.addUpdateListener(new AnimatorUpdateListener() {
    148. @Override
    149. public void onAnimationUpdate(ValueAnimator mAnim) {
    150. // 0.0 -> 1.0f
    151. float percent = mAnim.getAnimatedFraction();
    152. PointF p = GeometryUtil.getPointByPercent(tempDragCenter, mStickCenter, percent);
    153. updateDragCenter(p.x, p.y);
    154. }
    155. });
    156. mAnim.setInterpolator(new OvershootInterpolator(4));
    157. mAnim.setDuration(500);
    158. mAnim.start();
    159. }
    160. break;
    161. default:
    162. break;
    163. }
    164. return true;
    165. }
    166. /**
    167. * 更新拖拽圆圆心坐标,并重绘界面
    168. * @param x
    169. * @param y
    170. */
    171. private void updateDragCenter(float x, float y) {
    172. mDragCenter.set(x, y);
    173. invalidate();
    174. }
    175. @Override
    176. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    177. super.onSizeChanged(w, h, oldw, oldh);
    178. statusBarHeight = Utils.getStatusBarHeight(this);
    179. }
    180. }
    GeometryUtil
    1. /**
    2. * 几何图形工具
    3. */
    4. public class GeometryUtil {
    5. /**
    6. * As meaning of method name.
    7. * 获得两点之间的距离
    8. * @param p0
    9. * @param p1
    10. * @return
    11. */
    12. public static float getDistanceBetween2Points(PointF p0, PointF p1) {
    13. float distance = (float) Math.sqrt(Math.pow(p0.y - p1.y, 2) + Math.pow(p0.x - p1.x, 2));
    14. return distance;
    15. }
    16. /**
    17. * Get middle point between p1 and p2.
    18. * 获得两点连线的中点
    19. * @param p1
    20. * @param p2
    21. * @return
    22. */
    23. public static PointF getMiddlePoint(PointF p1, PointF p2) {
    24. return new PointF((p1.x + p2.x) / 2.0f, (p1.y + p2.y) / 2.0f);
    25. }
    26. /**
    27. * Get point between p1 and p2 by percent.
    28. * 根据百分比获取两点之间的某个点坐标
    29. * @param p1
    30. * @param p2
    31. * @param percent
    32. * @return
    33. */
    34. public static PointF getPointByPercent(PointF p1, PointF p2, float percent) {
    35. return new PointF(evaluateValue(percent, p1.x , p2.x), evaluateValue(percent, p1.y , p2.y));
    36. }
    37. /**
    38. * 根据分度值,计算从start到end中,fraction位置的值。fraction范围为0 -> 1
    39. * @param fraction
    40. * @param start
    41. * @param end
    42. * @return
    43. */
    44. public static float evaluateValue(float fraction, Number start, Number end){
    45. return start.floatValue() + (end.floatValue() - start.floatValue()) * fraction;
    46. }
    47. /**
    48. * Get the point of intersection between circle and line.
    49. * 获取 通过指定圆心,斜率为lineK的直线与圆的交点。
    50. *
    51. * @param pMiddle The circle center point.
    52. * @param radius The circle radius.
    53. * @param lineK The slope of line which cross the pMiddle.
    54. * @return
    55. */
    56. public static PointF[] getIntersectionPoints(PointF pMiddle, float radius, Double lineK) {
    57. PointF[] points = new PointF[2];
    58. float radian, xOffset = 0, yOffset = 0;
    59. if(lineK != null){
    60. radian= (float) Math.atan(lineK);
    61. xOffset = (float) (Math.sin(radian) * radius);
    62. yOffset = (float) (Math.cos(radian) * radius);
    63. }else {
    64. xOffset = radius;
    65. yOffset = 0;
    66. }
    67. points[0] = new PointF(pMiddle.x + xOffset, pMiddle.y - yOffset);
    68. points[1] = new PointF(pMiddle.x - xOffset, pMiddle.y + yOffset);
    69. return points;
    70. }
    71. }





    附件列表

    • 相关阅读:
      POJ 2923 Relocation (状态压缩,01背包)
      HDU 2126 Buy the souvenirs (01背包,输出方案数)
      hdu 2639 Bone Collector II (01背包,求第k优解)
      UVA 562 Dividing coins (01背包)
      POJ 3437 Tree Grafting
      Light OJ 1095 Arrange the Numbers(容斥)
      BZOJ 1560 火星藏宝图(DP)
      POJ 3675 Telescope
      POJ 2986 A Triangle and a Circle
      BZOJ 1040 骑士
    • 原文地址:https://www.cnblogs.com/sixrain/p/5041965.html
    Copyright © 2011-2022 走看看