11.粘性控件

粘性控件 (对View的自定义)
* 应用场景: 未读提醒的清除
* 功能实现:

> 1. 画静态图 OK

> 2. 把静态的数值变成变量(计算得到真实的变量) OK

> 3. 不断地修改变量, 重绘界面, 动起来了.

> 4. 功能分析:
    a. 拖拽超出范围,断开, 松手, 消失
    b. 拖拽超出范围,断开,放回去了,恢复
    c. 拖拽没超出范围, 松手,弹回去

没有布局:

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

来自为知笔记(Wiz)

附件列表

时间: 2024-10-16 03:29:52

11.粘性控件的相关文章

自定义控件进阶02_侧滑删除,粘性控件

1 快速索引 细节问题: 1.1 把当前被选中的字母索引置为灰色,否则为白色 每一次在快速索引栏上的触摸事件都触发invalidate(),重走onDraw()方法 在onDraw()方法里,做判断,如果通过触摸事件计算的索引与绘制字母数组的索引一致时就更改画笔的颜色,(记得在触摸事件中如果手指抬起,就把计算的索引置为-1) 1.2 弹出吐司不太好看,弹出一个圆角的矩形框会好看一些(实际上就是一个圆角的TextView,平常隐藏,滑动的时候显示) 圆角:定义背景的xml文件,shape根节点,弧

Android粘性控件,滑动停留StickLayout(导航栏滑动停留)

我们平时在使用APP的时候,经常可以见到一些导航栏滑到顶端就停留,而下面的控件可以接着滑动:今天,我就给大家介绍一个非常好用的滑动粘性控件StickLayout,它不仅可以让其任意一个直接子控件滑动停留在顶端,而且还可以设置滑动到指定直接子控件,并且配有滑动改变监听,可以轻松实现滑动时的联动操作:我们用该控件就可以轻松实现像支付宝"所有应用"界面效果,下面我们就一起学习一下吧. ???首先,我们来看一下效果演示图: Note:图1为设置属性wkp_canScrollToEndViewT

使用 IntraWeb (11) - 基本控件之 TIWButton

今天有幸被召回母校给即将毕业的学弟学妹们讲我这两年的工作史,看了下母校没啥特别的变化,就是寝室都安了空调,学妹们都非常漂亮而已..好了不扯蛋了,说下今天的主题吧.这些天我在深度定制语法高亮功能的同时发现了博客园提供的一些有意思的函数,甚至有几个博客园都没用到,我也不知道怎么才能触发那些功能..打开这个js就可以看到很多好用的东西了,虽然写的不怎么样,但是至少有这些功能. ps: 推荐安装一个代码格式化的插件,否则一坨看着蛋疼.比如第一个就是 log,方便调试. pinterest.com/sda

HTML5学习总结-11 IOS 控件WebView显示网页

1.使用UIWebView加载网页 运行XCode  新建一个Single View Application . 2 添加安全消息 添加以下消息到项目的  Info.plist <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key><true/> </dict> 2.加载WebView 在ViewController.m添加Web

Asp.Net服务端的基本控件

今天开始把最基础的Asp.Net服务端基本控件学习巩固了一下 1.Asp.Net服务端控件是Asp.Net对HTML的封装,在C#代码中就可以用txt1.Text="指定值"这种方式修改 input的值,Asp.Net会将服务端控件渲染成HTML代码输出给浏览器,服务端控件是Asp.Net非常容易上手,也非常吸引初学者,但也是被人诟病的东西.因为它会传输很多无法的东西,如viewstate. 服务端控件在内网或互联网系统的后台部分等访问频率不高的地方还是很适合的. 服务端控件只能用po

夺命雷公狗---微信开发58----微网站之jquery_mobile之控件介绍

我们上一节课里面介绍了基本的jqm是如何用的了,那么这一节课我们就开始玩玩他的控件 1...布局网格 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <!--宽高禁缩放 --> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-sca

Android 控件使用

1.Android控件之TextView探究 2.Android控件之EditView探究 3.Android控件之CheckBox.RadioButton探究 4.Android控件之ImageView探究 5.Android控件之GridView探究 6.Android控件之ListView探究一 7.Android控件之ListView探究二 8.Android控件之ToggleButton探究 9.Android控件之DatePicker.TimePicker探究 10.Android控

解析大型.NET ERP系统 灵活复杂的界面控件Infragistics WinForms

Infragistics 是.NET平台优秀的控件供应商,囊括了WinForms,ASP.NET,Silverlight,WPF,Windows Phone等所有关于微软.NET技术的界面控件.借助于这些功能复杂的控件,为ERP的界面提供了灵活的操作能力. 本篇不谈控件开发,只详细说明ERP系统如何使用Infragistics WinForms,而不用.NET 自带的控件. 1  文本编辑控件提示必须输入值 如果一个文本编辑控件必须输入值,有许多实现方法可以借鉴.看金蝶ERP的实现,在文本标签控

ListView控件使用简介

ListView控件在各类程序中,具有数据显示直观,操作方便的特点.所以使用率极高,但控件的各类参数众多,很多初学者不易掌握,在此列举该控件的一些常用方法,属性,希望对初学者有一定帮助. 1 //2005年10月9日 2 //ListView标头的代码创建方法. 3 ColumnHeader title=new ColumnHeader(); //声明标头,并创建对象. 4 title.Text="标头1名称"; //标头一显示的名称. 5 title.Width=120; //标头一