日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

11.粘性控件

發(fā)布時(shí)間:2023/12/10 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 11.粘性控件 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
粘性控件 (對(duì)View的自定義)
*?應(yīng)用場(chǎng)景: 未讀提醒的清除
*?功能實(shí)現(xiàn):
> 1. 畫(huà)靜態(tài)圖 OK
> 2. 把靜態(tài)的數(shù)值變成變量(計(jì)算得到真實(shí)的變量) OK?
> 3. 不斷地修改變量, 重繪界面, 動(dòng)起來(lái)了.
> 4. 功能分析:
????a. 拖拽超出范圍,斷開(kāi), 松手, 消失
????b. 拖拽超出范圍,斷開(kāi),放回去了,恢復(fù)
????c. 拖拽沒(méi)超出范圍, 松手,彈回去

沒(méi)有布局:MainActivity
  • public class MainActivity extends Activity {
  • @Override
  • protected void onCreate(Bundle savedInstanceState) {
  • super.onCreate(savedInstanceState);
  • requestWindowFeature(Window.FEATURE_NO_TITLE);
  • setContentView(new GooView(MainActivity.this));
  • }
  • }
  • Utils
  • public class Utils {
  • public static Toast mToast;
  • public static void showToast(Context mContext, String msg) {
  • if (mToast == null) {
  • mToast = Toast.makeText(mContext, "", Toast.LENGTH_SHORT);
  • }
  • mToast.setText(msg);
  • mToast.show();
  • }
  • /**
  • * dip 轉(zhuǎn)換成 px
  • * @param dip
  • * @param context
  • * @return
  • */
  • public static float dip2Dimension(float dip, Context context) {
  • DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
  • return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
  • }
  • /**
  • * @param dip
  • * @param context
  • * @param complexUnit {@link TypedValue#COMPLEX_UNIT_DIP} {@link TypedValue#COMPLEX_UNIT_SP}}
  • * @return
  • */
  • public static float toDimension(float dip, Context context, int complexUnit) {
  • DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
  • return TypedValue.applyDimension(complexUnit, dip, displayMetrics);
  • }
  • /** 獲取狀態(tài)欄高度
  • * @param v
  • * @return
  • */
  • public static int getStatusBarHeight(View v) {
  • if (v == null) {
  • return 0;
  • }
  • Rect frame = new Rect();
  • v.getWindowVisibleDisplayFrame(frame);
  • return frame.top;
  • }
  • public static String getActionName(MotionEvent event) {
  • String action = "unknow";
  • switch (MotionEventCompat.getActionMasked(event)) {
  • case MotionEvent.ACTION_DOWN:
  • action = "ACTION_DOWN";
  • break;
  • case MotionEvent.ACTION_MOVE:
  • action = "ACTION_MOVE";
  • break;
  • case MotionEvent.ACTION_UP:
  • action = "ACTION_UP";
  • break;
  • case MotionEvent.ACTION_CANCEL:
  • action = "ACTION_CANCEL";
  • break;
  • case MotionEvent.ACTION_SCROLL:
  • action = "ACTION_SCROLL";
  • break;
  • case MotionEvent.ACTION_OUTSIDE:
  • action = "ACTION_SCROLL";
  • break;
  • default:
  • break;
  • }
  • return action;
  • }
  • }
  • GooView
  • /**
  • * 粘性控件
  • * @author poplar
  • *
  • */
  • public class GooView extends View {
  • private static final String TAG = "TAG";
  • private Paint mPaint;
  • public GooView(Context context) {
  • this(context, null);
  • }
  • public GooView(Context context, AttributeSet attrs) {
  • this(context, attrs , 0);
  • }
  • public GooView(Context context, AttributeSet attrs, int defStyle) {
  • super(context, attrs, defStyle);
  • // 做初始化操作
  • mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  • mPaint.setColor(Color.RED);
  • }
  • PointF[] mStickPoints = new PointF[]{
  • new PointF(250f, 250f),
  • new PointF(250f, 350f)
  • };
  • PointF[] mDragPoints = new PointF[]{
  • new PointF(50f, 250f),
  • new PointF(50f, 350f)
  • };
  • PointF mControlPoint = new PointF(150f, 300f);
  • PointF mDragCenter = new PointF(80f, 80f);
  • float mDragRadius = 14f;
  • PointF mStickCenter = new PointF(150f, 150f);
  • float mStickRadius = 12f;
  • private int statusBarHeight;
  • float farestDistance = 80f;
  • private boolean isOutofRange;
  • private boolean isDisappear;
  • @Override
  • protected void onDraw(Canvas canvas) {
  • // 計(jì)算連接點(diǎn)值, 控制點(diǎn), 固定圓半徑
  • // 1. 獲取固定圓半徑(根據(jù)兩圓圓心距離)
  • float tempStickRadius = getTempStickRadius();
  • // 2. 獲取直線與圓的交點(diǎn)
  • float yOffset = mStickCenter.y - mDragCenter.y;
  • float xOffset = mStickCenter.x - mDragCenter.x;
  • Double lineK = null;
  • if(xOffset != 0){
  • lineK = (double) (yOffset / xOffset);
  • }
  • // 通過(guò)幾何圖形工具獲取交點(diǎn)坐標(biāo)
  • mDragPoints = GeometryUtil.getIntersectionPoints(mDragCenter, mDragRadius, lineK);
  • mStickPoints = GeometryUtil.getIntersectionPoints(mStickCenter, tempStickRadius, lineK);
  • // 3. 獲取控制點(diǎn)坐標(biāo)
  • mControlPoint = GeometryUtil.getMiddlePoint(mDragCenter, mStickCenter);
  • // 保存畫(huà)布狀態(tài)
  • canvas.save();
  • canvas.translate(0, -statusBarHeight);
  • // 畫(huà)出最大范圍(參考用)
  • mPaint.setStyle(Style.STROKE);
  • canvas.drawCircle(mStickCenter.x, mStickCenter.y, farestDistance, mPaint);
  • mPaint.setStyle(Style.FILL);
  • if(!isDisappear){
  • if(!isOutofRange){
  • // 3. 畫(huà)連接部分
  • Path path = new Path();
  • // 跳到點(diǎn)1
  • path.moveTo(mStickPoints[0].x, mStickPoints[0].y);
  • // 畫(huà)曲線1 -> 2
  • path.quadTo(mControlPoint.x, mControlPoint.y, mDragPoints[0].x, mDragPoints[0].y);
  • // 畫(huà)直線2 -> 3
  • path.lineTo(mDragPoints[1].x, mDragPoints[1].y);
  • // 畫(huà)曲線3 -> 4
  • path.quadTo(mControlPoint.x, mControlPoint.y, mStickPoints[1].x, mStickPoints[1].y);
  • path.close();
  • canvas.drawPath(path, mPaint);
  • // 畫(huà)附著點(diǎn)(參考用)
  • mPaint.setColor(Color.BLUE);
  • canvas.drawCircle(mDragPoints[0].x, mDragPoints[0].y, 3f, mPaint);
  • canvas.drawCircle(mDragPoints[1].x, mDragPoints[1].y, 3f, mPaint);
  • canvas.drawCircle(mStickPoints[0].x, mStickPoints[0].y, 3f, mPaint);
  • canvas.drawCircle(mStickPoints[1].x, mStickPoints[1].y, 3f, mPaint);
  • mPaint.setColor(Color.RED);
  • // 2. 畫(huà)固定圓
  • canvas.drawCircle(mStickCenter.x, mStickCenter.y, tempStickRadius, mPaint);
  • }
  • // 1. 畫(huà)拖拽圓
  • canvas.drawCircle(mDragCenter.x, mDragCenter.y, mDragRadius, mPaint);
  • }
  • // 恢復(fù)上次的保存狀態(tài)
  • canvas.restore();
  • }
  • // 獲取固定圓半徑(根據(jù)兩圓圓心距離)
  • private float getTempStickRadius() {
  • float distance = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter);
  • // if(distance> farestDistance){
  • // distance = farestDistance;
  • // }
  • distance = Math.min(distance, farestDistance);
  • // 0.0f -> 1.0f
  • float percent = distance / farestDistance;
  • Log.d(TAG, "percent: " + percent);
  • // percent , 100% -> 20%
  • return evaluate(percent, mStickRadius, mStickRadius * 0.2f);
  • }
  • public Float evaluate(float fraction, Number startValue, Number endValue) {
  • float startFloat = startValue.floatValue();
  • return startFloat + fraction * (endValue.floatValue() - startFloat);
  • }
  • @Override
  • public boolean onTouchEvent(MotionEvent event) {
  • float x;
  • float y;
  • switch (event.getAction()) {
  • case MotionEvent.ACTION_DOWN:
  • isOutofRange = false;
  • isDisappear = false;
  • x = event.getRawX();
  • y = event.getRawY();
  • updateDragCenter(x, y);
  • break;
  • case MotionEvent.ACTION_MOVE:
  • x = event.getRawX();
  • y = event.getRawY();
  • updateDragCenter(x, y);
  • // 處理斷開(kāi)事件
  • float distance = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter);
  • if(distance > farestDistance){
  • isOutofRange = true;
  • invalidate();
  • }
  • break;
  • case MotionEvent.ACTION_UP:
  • if(isOutofRange){
  • float d = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter);
  • if(d > farestDistance){
  • // a. 拖拽超出范圍,斷開(kāi), 松手, 消失
  • isDisappear = true;
  • invalidate();
  • }else {
  • //b. 拖拽超出范圍,斷開(kāi),放回去了,恢復(fù)
  • updateDragCenter(mStickCenter.x, mStickCenter.y);
  • }
  • }else {
  • // c. 拖拽沒(méi)超出范圍, 松手,彈回去
  • final PointF tempDragCenter = new PointF(mDragCenter.x, mDragCenter.y);
  • ValueAnimator mAnim = ValueAnimator.ofFloat(1.0f);
  • mAnim.addUpdateListener(new AnimatorUpdateListener() {
  • @Override
  • public void onAnimationUpdate(ValueAnimator mAnim) {
  • // 0.0 -> 1.0f
  • float percent = mAnim.getAnimatedFraction();
  • PointF p = GeometryUtil.getPointByPercent(tempDragCenter, mStickCenter, percent);
  • updateDragCenter(p.x, p.y);
  • }
  • });
  • mAnim.setInterpolator(new OvershootInterpolator(4));
  • mAnim.setDuration(500);
  • mAnim.start();
  • }
  • break;
  • default:
  • break;
  • }
  • return true;
  • }
  • /**
  • * 更新拖拽圓圓心坐標(biāo),并重繪界面
  • * @param x
  • * @param y
  • */
  • private void updateDragCenter(float x, float y) {
  • mDragCenter.set(x, y);
  • invalidate();
  • }
  • @Override
  • protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  • super.onSizeChanged(w, h, oldw, oldh);
  • statusBarHeight = Utils.getStatusBarHeight(this);
  • }
  • }
  • GeometryUtil
  • /**
  • * 幾何圖形工具
  • */
  • public class GeometryUtil {
  • /**
  • * As meaning of method name.
  • * 獲得兩點(diǎn)之間的距離
  • * @param p0
  • * @param p1
  • * @return
  • */
  • public static float getDistanceBetween2Points(PointF p0, PointF p1) {
  • float distance = (float) Math.sqrt(Math.pow(p0.y - p1.y, 2) + Math.pow(p0.x - p1.x, 2));
  • return distance;
  • }
  • /**
  • * Get middle point between p1 and p2.
  • * 獲得兩點(diǎn)連線的中點(diǎn)
  • * @param p1
  • * @param p2
  • * @return
  • */
  • public static PointF getMiddlePoint(PointF p1, PointF p2) {
  • return new PointF((p1.x + p2.x) / 2.0f, (p1.y + p2.y) / 2.0f);
  • }
  • /**
  • * Get point between p1 and p2 by percent.
  • * 根據(jù)百分比獲取兩點(diǎn)之間的某個(gè)點(diǎn)坐標(biāo)
  • * @param p1
  • * @param p2
  • * @param percent
  • * @return
  • */
  • public static PointF getPointByPercent(PointF p1, PointF p2, float percent) {
  • return new PointF(evaluateValue(percent, p1.x , p2.x), evaluateValue(percent, p1.y , p2.y));
  • }
  • /**
  • * 根據(jù)分度值,計(jì)算從start到end中,fraction位置的值。fraction范圍為0 -> 1
  • * @param fraction
  • * @param start
  • * @param end
  • * @return
  • */
  • public static float evaluateValue(float fraction, Number start, Number end){
  • return start.floatValue() + (end.floatValue() - start.floatValue()) * fraction;
  • }
  • /**
  • * Get the point of intersection between circle and line.
  • * 獲取 通過(guò)指定圓心,斜率為lineK的直線與圓的交點(diǎn)。
  • *
  • * @param pMiddle The circle center point.
  • * @param radius The circle radius.
  • * @param lineK The slope of line which cross the pMiddle.
  • * @return
  • */
  • public static PointF[] getIntersectionPoints(PointF pMiddle, float radius, Double lineK) {
  • PointF[] points = new PointF[2];
  • float radian, xOffset = 0, yOffset = 0;
  • if(lineK != null){
  • radian= (float) Math.atan(lineK);
  • xOffset = (float) (Math.sin(radian) * radius);
  • yOffset = (float) (Math.cos(radian) * radius);
  • }else {
  • xOffset = radius;
  • yOffset = 0;
  • }
  • points[0] = new PointF(pMiddle.x + xOffset, pMiddle.y - yOffset);
  • points[1] = new PointF(pMiddle.x - xOffset, pMiddle.y + yOffset);
  • return points;
  • }
  • }



  • 來(lái)自為知筆記(Wiz)

    附件列表

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/sixrain/p/5041965.html

    總結(jié)

    以上是生活随笔為你收集整理的11.粘性控件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。