欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實(shí)現(xiàn)滾動(dòng)刻度尺效果

 更新時(shí)間:2017年05月27日 10:14:09   作者:LichFaker  
本篇文章主要介紹了Android實(shí)現(xiàn)滾動(dòng)刻度尺效果,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

緣起

最近在幫人做一個(gè)計(jì)步器,其中涉及到身高、體重等信息的采集;我參考了眾多app的實(shí)現(xiàn),覺得"樂(lè)動(dòng)力"中滑動(dòng)刻度的方式比較優(yōu)雅。于是乎,反編譯了該app,結(jié)果發(fā)現(xiàn)它是采用圖片的方式實(shí)現(xiàn)的,即ScrollView內(nèi)嵌了一張帶刻度的圖片。
個(gè)人覺得該方式太不靈活,且對(duì)美工的依賴較大,于是便想自定義一個(gè)刻度尺控件。

需求分析

  1. 繪制刻度,區(qū)分整值刻度和普通刻度
  2. 紅色指針始終在刻度尺的中間,表示當(dāng)前的刻度
  3. 刻度的最大值和最小值可動(dòng)態(tài)設(shè)置
  4. 刻度尺的高度或?qū)挾瓤稍O(shè)置,設(shè)置后中間刻度不變
  5. 可滑動(dòng),滑動(dòng)后當(dāng)前刻度隨之改變

涉及的知識(shí)點(diǎn)

  1. View的機(jī)制
  2. canvas繪圖
  3. Scroller工具類的使用
  4. 自定義View的屬性
  5. 點(diǎn)擊、滑動(dòng)事件的處理

最終效果

由于簡(jiǎn)書上無(wú)法嵌入gif,為不影響效果,請(qǐng)移步github查看,如果覺得不錯(cuò),幫忙給個(gè)star ^_^https://github.com/LichFaker/ScaleView

實(shí)現(xiàn)過(guò)程

1、新建一個(gè)class:HorizontalScaleScrollView, 繼承自View

2、在構(gòu)造方法中獲取自定義屬性:

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,計(jì)算中間刻度

@Override
protected 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);
 //每一屏幕刻度的個(gè)數(shù)/2
 int countScale = mScaleScrollViewRange / mScaleMargin / 2;
 //根據(jù)滑動(dòng)的距離,計(jì)算指針的位置【指針始終位于屏幕中間】
 int finalX = mScroller.getFinalX();
 //滑動(dòng)的刻度
 int tmpCountScale = (int) Math.rint((double) finalX / (double) mScaleMargin);//四舍五入取整
 //總刻度
 mCountScale = tmpCountScale + countScale + mMin;
 if (mScrollListener != null) { //回調(diào)方法
   mScrollListener.onScaleScroll(mCountScale);
 }
 canvas.drawLine(countScale * mScaleMargin + finalX, mRectHeight,
     countScale * mScaleMargin + finalX, mRectHeight - mScaleMaxHeight - mScaleHeight, paint);
}

處理滑動(dòng)事件

  1. 在手指按下時(shí),記錄當(dāng)前的x坐標(biāo)(針對(duì)水平刻度尺)。
  2. 在手指滑動(dòng)過(guò)程中,判斷當(dāng)前指針?biāo)傅目潭仁欠褚呀?jīng)超出了邊界,如果超出,則禁止滑動(dòng),同時(shí)刷新當(dāng)前界面。
  3. 在手指抬起時(shí),校正當(dāng)前的刻度。
@Override
public 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) { //向右邊滑動(dòng)
        if (mCountScale <= mMin && dataX <= 0) //禁止繼續(xù)向右滑動(dòng)
          return super.onTouchEvent(event);
      } else if (mCountScale - mTempScale > 0) { //向左邊滑動(dòng)
        if (mCountScale >= mMax && dataX >= 0) //禁止繼續(xù)向左滑動(dòng)
          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);
}

最后的說(shuō)明

以上只是針對(duì)水平滑動(dòng)刻度的實(shí)現(xiàn),垂直滑動(dòng)原理一致,在源碼中已經(jīng)實(shí)現(xiàn),其中也有許多不夠完善的地方,如:

  1. 第一次快速滑動(dòng)時(shí),可以超出邊界,之后則不會(huì);
  2. 開放的自定義屬性不夠(根據(jù)具體情況);
  3. 可以考慮將水平和垂直的實(shí)現(xiàn),在一個(gè)類中完成,因?yàn)樵趯?shí)現(xiàn)過(guò)程中發(fā)現(xiàn)其實(shí)有很多代碼都是類似的,只是個(gè)別參數(shù)屬性的不同,在坐標(biāo)系中,垂直可以看成是水平旋轉(zhuǎn)了90°,之后有時(shí)間可以朝這個(gè)方向嘗試下。

相關(guān)文章

最新評(píng)論