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. }





    附件列表

    • 相关阅读:
      HDOJ_ACM_统计问题
      HDOJ_ACM_Queuing
      HDOJ_ACM_数塔
      HDOJ_ACM_免费馅饼
      HDOJ_ACM_FatMouse's Speed
      HDOJ_ACM_Monkey and Banana
      斐波南希数列
      .net framework 2.0的WinForm的ShowInTaskBar属性的bug
      寂寞的季节
      广告一下
    • 原文地址:https://www.cnblogs.com/sixrain/p/5041965.html
    Copyright © 2011-2022 走看看