国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android實現滾動刻度尺效果

2019-10-23 18:27:44
字體:
來源:轉載
供稿:網友

緣起

最近在幫人做一個計步器,其中涉及到身高、體重等信息的采集;我參考了眾多app的實現,覺得"樂動力"中滑動刻度的方式比較優雅。于是乎,反編譯了該app,結果發現它是采用圖片的方式實現的,即ScrollView內嵌了一張帶刻度的圖片。
個人覺得該方式太不靈活,且對美工的依賴較大,于是便想自定義一個刻度尺控件。

需求分析

  1. 繪制刻度,區分整值刻度和普通刻度
  2. 紅色指針始終在刻度尺的中間,表示當前的刻度
  3. 刻度的最大值和最小值可動態設置
  4. 刻度尺的高度或寬度可設置,設置后中間刻度不變
  5. 可滑動,滑動后當前刻度隨之改變

涉及的知識點

  1. View的機制
  2. canvas繪圖
  3. Scroller工具類的使用
  4. 自定義View的屬性
  5. 點擊、滑動事件的處理

最終效果

由于簡書上無法嵌入gif,為不影響效果,請移步github查看,如果覺得不錯,幫忙給個star ^_^https://github.com/LichFaker/ScaleView

實現過程

1、新建一個class:HorizontalScaleScrollView, 繼承自View

2、在構造方法中獲取自定義屬性:

protected void init(AttributeSet attrs) {   // 獲取自定義屬性   TypedArray ta = getContext().obtainStyledAttributes(attrs, ATTR);   mMin = ta.getInteger(LF_SCALE_MIN, 0);   mMax = ta.getInteger(LF_SCALE_MAX, 200);   mScaleMargin = ta.getDimensionPixelOffset(LF_SCALE_MARGIN, 15);   mScaleHeight = ta.getDimensionPixelOffset(LF_SCALE_HEIGHT, 20);   ta.recycle();   mScroller = new Scroller(getContext());  }

3、重寫onMeasure,計算中間刻度

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height=MeasureSpec.makeMeasureSpec(mRectHeight, MeasureSpec.AT_MOST);   super.onMeasure(widthMeasureSpec, height);     mScaleScrollViewRange = getMeasuredWidth();   mTempScale = mScaleScrollViewRange / mScaleMargin / 2 + mMin;   mMidCountScale = mScaleScrollViewRange / mScaleMargin / 2 + mMin;}

4、重寫onDraw,繪制刻度和指針

protected void onDrawScale(Canvas canvas, Paint paint) {   paint.setTextSize(mRectHeight / 4); for (int i = 0, k = mMin; i <= mMax - mMin; i++) {   if (i % 10 == 0) {      //整值     canvas.drawLine(i * mScaleMargin, mRectHeight, i * mScaleMargin, mRectHeight - mScaleMaxHeight, paint);      //整值文字     canvas.drawText(String.valueOf(k), i * mScaleMargin, mRectHeight - mScaleMaxHeight - 20, paint);     k += 10;   } else {     canvas.drawLine(i * mScaleMargin, mRectHeight, i * mScaleMargin, mRectHeight - mScaleHeight, paint);    } }}
protected void onDrawPointer(Canvas canvas, Paint paint) { paint.setColor(Color.RED); //每一屏幕刻度的個數/2 int countScale = mScaleScrollViewRange / mScaleMargin / 2; //根據滑動的距離,計算指針的位置【指針始終位于屏幕中間】 int finalX = mScroller.getFinalX(); //滑動的刻度 int tmpCountScale = (int) Math.rint((double) finalX / (double) mScaleMargin);//四舍五入取整 //總刻度 mCountScale = tmpCountScale + countScale + mMin; if (mScrollListener != null) { //回調方法   mScrollListener.onScaleScroll(mCountScale); } canvas.drawLine(countScale * mScaleMargin + finalX, mRectHeight,     countScale * mScaleMargin + finalX, mRectHeight - mScaleMaxHeight - mScaleHeight, paint);}

處理滑動事件

  1. 在手指按下時,記錄當前的x坐標(針對水平刻度尺)。
  2. 在手指滑動過程中,判斷當前指針所指的刻度是否已經超出了邊界,如果超出,則禁止滑動,同時刷新當前界面。
  3. 在手指抬起時,校正當前的刻度。
@Overridepublic boolean onTouchEvent(MotionEvent event) {  int x = (int) event.getX();  switch (event.getAction()) {    case MotionEvent.ACTION_DOWN:      if (mScroller != null && !mScroller.isFinished()) {        mScroller.abortAnimation();      }      mScrollLastX = x;      return true;    case MotionEvent.ACTION_MOVE:      int dataX = mScrollLastX - x;      if (mCountScale - mTempScale < 0) { //向右邊滑動        if (mCountScale <= mMin && dataX <= 0) //禁止繼續向右滑動          return super.onTouchEvent(event);      } else if (mCountScale - mTempScale > 0) { //向左邊滑動        if (mCountScale >= mMax && dataX >= 0) //禁止繼續向左滑動          return super.onTouchEvent(event);      }      smoothScrollBy(dataX, 0);      mScrollLastX = x;      postInvalidate();      mTempScale = mCountScale;      return true;    case MotionEvent.ACTION_UP:      if (mCountScale < mMin) mCountScale = mMin;      if (mCountScale > mMax) mCountScale = mMax;      int finalX = (mCountScale - mMidCountScale) * mScaleMargin;      mScroller.setFinalX(finalX); //糾正指針位置      postInvalidate();      return true;  }  return super.onTouchEvent(event);}

最后的說明

以上只是針對水平滑動刻度的實現,垂直滑動原理一致,在源碼中已經實現,其中也有許多不夠完善的地方,如:

  1. 第一次快速滑動時,可以超出邊界,之后則不會;
  2. 開放的自定義屬性不夠(根據具體情況);
  3. 可以考慮將水平和垂直的實現,在一個類中完成,因為在實現過程中發現其實有很多代碼都是類似的,只是個別參數屬性的不同,在坐標系中,垂直可以看成是水平旋轉了90°,之后有時間可以朝這個方向嘗試下。

注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 图木舒克市| 应用必备| 德江县| 河东区| 玉田县| 平罗县| 乾安县| 文水县| 锡林郭勒盟| 赤水市| 枝江市| 常州市| 府谷县| 武邑县| 嘉兴市| 军事| 隆德县| 闽清县| 永昌县| 汽车| 石狮市| 彝良县| 杭锦后旗| 民勤县| 清苑县| 桐城市| 淳安县| 霍邱县| 依兰县| 安溪县| 新河县| 内江市| 古蔺县| 会昌县| 邳州市| 临沧市| 石楼县| 平遥县| 龙游县| 阜阳市| 莱芜市|