溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Kotlin如何自定義View之標(biāo)尺控件

發(fā)布時(shí)間:2021-08-04 14:08:40 來(lái)源:億速云 閱讀:174 作者:小新 欄目:移動(dòng)開(kāi)發(fā)

這篇文章主要介紹Kotlin如何自定義View之標(biāo)尺控件,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

按照慣例,我們先來(lái)看看效果圖

Kotlin如何自定義View之標(biāo)尺控件

一、先總結(jié)下自定義View的步驟:

1、自定義View的屬性

2、在View的構(gòu)造方法中獲得我們自定義的屬性

3、重寫onMesure

4、重寫onDraw

其中onMesure方法不一定要重寫,但大部分情況下還是需要重寫的

二、View 的幾個(gè)構(gòu)造函數(shù)

1、constructor(mContext: Context)

—>java代碼直接new一個(gè)RulerView實(shí)例的時(shí)候,會(huì)調(diào)用這個(gè)只有一個(gè)參數(shù)的構(gòu)造函數(shù);

2、constructor(mContext: Context, attrs: AttributeSet)

—>在默認(rèn)的XML布局文件中創(chuàng)建的時(shí)候調(diào)用這個(gè)有兩個(gè)參數(shù)的構(gòu)造函數(shù)。AttributeSet類型的參數(shù)負(fù)責(zé)把XML布局文件中所自定義的屬性通過(guò)AttributeSet帶入到View內(nèi);

3、constructor(mContext: Context, attrs: AttributeSet,defStyleAttr:Int)

—>構(gòu)造函數(shù)中第三個(gè)參數(shù)是默認(rèn)的Style,這里的默認(rèn)的Style是指它在當(dāng)前Application或者Activity所用的Theme中的默認(rèn)Style,且只有在明確調(diào)用的時(shí)候才會(huì)調(diào)用

4、constructor(mContext: Context, attrs: AttributeSet,defStyleAttr:Int,defStyleRes:Int)

—>該構(gòu)造函數(shù)是在API21的時(shí)候才添加上的

三、下面我們就開(kāi)始來(lái)看看代碼啦

1、自定義View的屬性,首先在res/values/ 下建立一個(gè)attrs.xml , 在里面定義我們的需要用到的屬性以及聲明相對(duì)應(yīng)屬性的取值類型

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 android:layout_width="match_parent"
 android:layout_height="match_parent">

 <TextView
  android:id="@+id/tv_weight_tip"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="體重"
  android:textColor="@android:color/black"
  android:textSize="14dp"
  app:layout_constraintBottom_toBottomOf="parent"
  app:layout_constraintLeft_toLeftOf="parent"
  app:layout_constraintRight_toRightOf="parent"
  app:layout_constraintTop_toTopOf="parent"
  app:layout_constraintVertical_bias="0.132" />
 <RelativeLayout
  android:id="@+id/rl_weight_ruler"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  app:layout_constraintTop_toBottomOf="@+id/tv_weight_tip"
  app:layout_constraintLeft_toLeftOf="parent"
  app:layout_constraintRight_toRightOf="parent">

  <per.lijuan.rulerdome.RulerView
   android:id="@+id/ruler_weight"
   android:layout_width="match_parent"
   android:layout_height="58dp"
   android:layout_marginTop="24dp"
   app:alphaEnable="true"
   app:lineColor="@android:color/darker_gray"
   app:lineMaxHeight="40dp"
   app:lineMidHeight="30dp"
   app:lineMinHeight="20dp"
   app:lineSpaceWidth="10dp"
   app:lineWidth="2.5dp"
   app:textColor="@android:color/black"
   app:minValue="20"
   app:maxValue="200"
   app:perValue="0.1"
   app:selectorValue="55"/>

  <ImageView
   android:layout_width="14dp"
   android:layout_height="46dp"
   android:layout_centerHorizontal="true"
   android:layout_marginTop="6dp"
   android:scaleType="fitXY"
   android:src="@mipmap/ic_arrow"/>
 </RelativeLayout>

 <TextView
  android:id="@+id/tv_weight"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_marginTop="11dp"
  android:maxHeight="30sp"
  android:textColor="@color/colorPrimary"
  android:textSize="24sp"
  app:layout_constraintTop_toBottomOf="@+id/rl_weight_ruler"
  app:layout_constraintEnd_toEndOf="parent"
  app:layout_constraintStart_toStartOf="parent"/>
</android.support.constraint.ConstraintLayout>

一定要引入xmlns:app=”http://schemas.android.com/apk/res-auto” ,Android Studio中我們可以使用res-atuo命名空間,就不用在添加自定義View全類名。

3、在View的構(gòu)造方法中,獲得我們的自定義的樣式

private var mMinVelocity:Int = 0
 private var mScroller: Scroller? = null//Scroller是一個(gè)專門用于處理滾動(dòng)效果的工具類 用mScroller記錄/計(jì)算View滾動(dòng)的位置,再重寫View的computeScroll(),完成實(shí)際的滾動(dòng)
 private var mVelocityTracker: VelocityTracker?=null//主要用跟蹤觸摸屏事件(flinging事件和其他gestures手勢(shì)事件)的速率。
 private var mWidth:Int = 0
 private var mHeight:Int = 0

 private var mSelectorValue=50f  // 未選擇時(shí) 默認(rèn)的值 滑動(dòng)后表示當(dāng)前中間指針正在指著的值
 private var mMaxValue=200f   // 最大數(shù)值
 private var mMinValue=100f   //最小的數(shù)值
 private var mPerValue=1f   //最小單位(如 1:表示每2條刻度差為1;0.1:表示每2條刻度差為0.1

 private var mLineSpaceWidth = 5f // 尺子刻度2條線之間的距離
 private var mLineWidth = 4f   // 尺子刻度的寬度
 private var mLineMaxHeight = 420f // 尺子刻度分為3中不同的高度。 mLineMaxHeight表示最長(zhǎng)的那根(也就是 10的倍數(shù)時(shí)的高度)
 private var mLineMidHeight = 30f // mLineMidHeight 表示中間的高度(也就是 5 15 25 等時(shí)的高度)
 private var mLineMinHeight = 17f // mLineMinHeight 表示最短的那個(gè)高度(也就是 1 2 3 4 等時(shí)的高度)

 private var mTextMarginTop = 10f
 private var mTextSize = 30f   //尺子刻度下方數(shù)字的大小
 private var mAlphaEnable=false  // 尺子 最左邊 最后邊是否需要透明 `(透明效果更好點(diǎn))
 private var mTextHeight = 0.toFloat()//尺子刻度下方數(shù)字的高度
 private var mTextPaint: Paint?=null // 尺子刻度下方數(shù)字(也就是每隔10個(gè)出現(xiàn)的數(shù)值)畫筆
 private var mLinePaint: Paint?=null // 尺子刻度線的畫筆

 private var mTotalLine:Int = 0  //共有多少條 刻度
 private var mMaxOffset:Int = 0  //所有刻度 共有多長(zhǎng)
 private var mOffset:Float = 0.toFloat()// 默認(rèn)狀態(tài)下,mSelectorValue所在的位置 位于尺子總刻度的位置
 private var mLastX:Int = 0
 private var mMove: Int = 0
 private lateinit var mListener: OnValueChangeListener// 滑動(dòng)后數(shù)值回調(diào)

 private var mLineColor:Int= Color.GRAY //刻度的顏色
 private var mTextColor:Int= Color.BLACK//文字的顏色

 constructor(mContext: Context) : super(mContext,null)

 constructor(mContext: Context, attrs: AttributeSet) : super(mContext, attrs,0)

 constructor(mContext: Context, attrs: AttributeSet,defStyleAttr:Int) : super(mContext, attrs,defStyleAttr) {
  init(mContext, attrs)
 }

 fun init(context: Context, attrs: AttributeSet){
  Log.d(TAG, "init")
  mScroller= Scroller(context)

  this.mLineSpaceWidth=myfloat(25.0f)
  this.mLineWidth=myfloat(2.0f)
  this.mLineMaxHeight=myfloat(100.0f)
  this.mLineMidHeight=myfloat(60.0f)
  this.mLineMinHeight=myfloat(40.0f)
  this.mTextHeight=myfloat(40.0f)

  val typedArray: TypedArray =context.obtainStyledAttributes(attrs,
    R.styleable.RulerView)

  mAlphaEnable= typedArray.getBoolean(R.styleable.RulerView_alphaEnable, mAlphaEnable)

  mLineSpaceWidth = typedArray.getDimension(R.styleable.RulerView_lineSpaceWidth, mLineSpaceWidth)
  mLineWidth = typedArray.getDimension(R.styleable.RulerView_lineWidth, mLineWidth)
  mLineMaxHeight = typedArray.getDimension(R.styleable.RulerView_lineMaxHeight, mLineMaxHeight)
  mLineMidHeight = typedArray.getDimension(R.styleable.RulerView_lineMidHeight, mLineMidHeight)
  mLineMinHeight = typedArray.getDimension(R.styleable.RulerView_lineMinHeight, mLineMinHeight)
  mLineColor = typedArray.getColor(R.styleable.RulerView_lineColor, mLineColor)

  mTextSize = typedArray.getDimension(R.styleable.RulerView_textSize, mTextSize)
  mTextColor = typedArray.getColor(R.styleable.RulerView_textColor, mTextColor)
  mTextMarginTop = typedArray.getDimension(R.styleable.RulerView_textMarginTop, mTextMarginTop)

  mSelectorValue = typedArray.getFloat(R.styleable.RulerView_selectorValue, 0.0f)
  mMinValue = typedArray.getFloat(R.styleable.RulerView_minValue, 0.0f)
  mMaxValue = typedArray.getFloat(R.styleable.RulerView_maxValue, 100.0f)
  mPerValue = typedArray.getFloat(R.styleable.RulerView_perValue, 0.1f)

  mMinVelocity= ViewConfiguration.get(getContext()).scaledMinimumFlingVelocity

  mTextPaint = Paint(Paint.ANTI_ALIAS_FLAG)
  mTextPaint!!.textSize = mTextSize
  mTextPaint!!.color = mTextColor
  mTextHeight = getFontHeight(mTextPaint!!)

  mLinePaint = Paint(Paint.ANTI_ALIAS_FLAG)
  mLinePaint!!.strokeWidth = mLineWidth
  mLinePaint!!.color = mLineColor
 }

我們重寫了3個(gè)構(gòu)造方法,在上面的構(gòu)造方法中說(shuō)過(guò)默認(rèn)的布局文件調(diào)用的是兩個(gè)參數(shù)的構(gòu)造方法,所以記得讓所有的構(gòu)造方法調(diào)用三個(gè)參數(shù)的構(gòu)造方法,然后在三個(gè)參數(shù)的構(gòu)造方法中獲得自定義屬性。
一開(kāi)始一個(gè)參數(shù)的構(gòu)造方法和兩個(gè)參數(shù)的構(gòu)造方法是這樣的:

constructor(mContext: Context) : super (mContext)

 constructor(mContext: Context, attrs: AttributeSet?) : super(mContext, attrs)

有一點(diǎn)要注意的是super應(yīng)該改成this,然后讓一個(gè)參數(shù)的構(gòu)造方法引用兩個(gè)參數(shù)的構(gòu)造方法,兩個(gè)參數(shù)的構(gòu)造方法引用三個(gè)參數(shù)的構(gòu)造方法,代碼如下:

constructor(mContext: Context) : this(mContext,null)

 constructor(mContext: Context, attrs: AttributeSet?) : this(mContext, attrs!!,0)

 constructor(mContext: Context, attrs: AttributeSet,defStyleAttr:Int) : super(mContext, attrs,defStyleAttr) {
  init(mContext, attrs)
 }

4、重寫onDraw方法

override fun onDraw(canvas: Canvas) {
  super.onDraw(canvas)
  var left: Float
  var height: Float
  var value: String
  var alpha = 0
  var scale: Float
  val srcPointX = mWidth / 2
  for (i in 0 until mTotalLine) {
   left = srcPointX.toFloat() + mOffset + i * mLineSpaceWidth

   if (left < 0 || left > mWidth) {
    continue //先畫默認(rèn)值在正中間,左右各一半的view。多余部分暫時(shí)不畫(也就是從默認(rèn)值在中間,畫旁邊左右的刻度線)
   }

   if (i % 10 == 0) {
    height = mLineMaxHeight
   } else if (i % 5 == 0) {
    height = mLineMidHeight
   } else {
    height = mLineMinHeight
   }
   if (mAlphaEnable) {
    scale = 1 - Math.abs(left - srcPointX) / srcPointX
    alpha = (255f * scale * scale).toInt()

    mLinePaint!!.setAlpha(alpha)
   }
   canvas.drawLine(left, 0f, left, height, mLinePaint)

   if (i % 10 == 0) {
    value = (mMinValue + i * mPerValue / 10).toInt().toString()
    if (mAlphaEnable) {
     mTextPaint!!.alpha = alpha
    }
    canvas.drawText(value, left - mTextPaint!!.measureText(value) / 2,
      height + mTextMarginTop + mTextHeight, mTextPaint) // 在為整數(shù)時(shí),畫 數(shù)值
   }
  }
 }

View的繪制流程是從ViewRoot的performTravarsals方法開(kāi)始的,經(jīng)過(guò)measure、layout和draw三個(gè)過(guò)程才能最終將一個(gè)View繪制出來(lái),其中:

測(cè)量——onMeasure():用來(lái)測(cè)量View的寬和高來(lái)決定View的大小
布局——onLayout():用來(lái)確定View在父容器ViewGroup中的放置位置
繪制——onDraw():負(fù)責(zé)將View繪制在屏幕上

5、重寫onTouchEvent方法

onTouchEvent()是View自帶的接口,Android系統(tǒng)提供了默認(rèn)的實(shí)現(xiàn),用于處理觸摸事件。當(dāng)我們對(duì)標(biāo)尺控件向左向右滑動(dòng)時(shí),此方法就會(huì)被調(diào)用。

override fun onTouchEvent(event: MotionEvent): Boolean {
    Log.d(TAG, "onTouchEvent")

    val action = event.action
    val xPosition = event.x.toInt()

    if (mVelocityTracker == null) {
      mVelocityTracker = VelocityTracker.obtain()
    }
    mVelocityTracker!!.addMovement(event)

    when (action) {
      MotionEvent.ACTION_DOWN -> {
        mScroller!!.forceFinished(true)
        mLastX = xPosition
        mMove = 0
      }
      MotionEvent.ACTION_MOVE -> {
        mMove = mLastX - xPosition
        changeMoveAndValue()
      }
      MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
        countMoveEnd()
        countVelocityTracker()
        return false
      }
      else -> {
      }
    }

    mLastX = xPosition
    return true
  }

現(xiàn)在我把完整的代碼貼出來(lái)

package per.lijuan.rulerdome

import android.content.Context
import android.content.res.TypedArray
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
import android.view.ViewConfiguration
import android.widget.Scroller

/**
 * Created by juan on 2018/5/11.
 */
class RulerView: View {
  private val TAG : String = "RulerView"

  private var mMinVelocity:Int = 0
  private var mScroller: Scroller? = null//Scroller是一個(gè)專門用于處理滾動(dòng)效果的工具類  用mScroller記錄/計(jì)算View滾動(dòng)的位置,再重寫View的computeScroll(),完成實(shí)際的滾動(dòng)
  private var mVelocityTracker: VelocityTracker?=null//主要用跟蹤觸摸屏事件(flinging事件和其他gestures手勢(shì)事件)的速率。
  private var mWidth:Int = 0
  private var mHeight:Int = 0

  private var mSelectorValue=50f   // 未選擇時(shí) 默認(rèn)的值 滑動(dòng)后表示當(dāng)前中間指針正在指著的值
  private var mMaxValue=200f     // 最大數(shù)值
  private var mMinValue=100f     //最小的數(shù)值
  private var mPerValue=1f      //最小單位(如 1:表示每2條刻度差為1;0.1:表示每2條刻度差為0.1

  private var mLineSpaceWidth = 5f  // 尺子刻度2條線之間的距離
  private var mLineWidth = 4f     // 尺子刻度的寬度
  private var mLineMaxHeight = 420f  // 尺子刻度分為3中不同的高度。 mLineMaxHeight表示最長(zhǎng)的那根(也就是 10的倍數(shù)時(shí)的高度)
  private var mLineMidHeight = 30f  // mLineMidHeight 表示中間的高度(也就是 5 15 25 等時(shí)的高度)
  private var mLineMinHeight = 17f  // mLineMinHeight 表示最短的那個(gè)高度(也就是 1 2 3 4 等時(shí)的高度)

  private var mTextMarginTop = 10f
  private var mTextSize = 30f     //尺子刻度下方數(shù)字的大小
  private var mAlphaEnable=false    // 尺子 最左邊 最后邊是否需要透明 `(透明效果更好點(diǎn))
  private var mTextHeight = 0.toFloat()//尺子刻度下方數(shù)字的高度
  private var mTextPaint: Paint?=null  // 尺子刻度下方數(shù)字(也就是每隔10個(gè)出現(xiàn)的數(shù)值)畫筆
  private var mLinePaint: Paint?=null  // 尺子刻度線的畫筆

  private var mTotalLine:Int = 0    //共有多少條 刻度
  private var mMaxOffset:Int = 0    //所有刻度 共有多長(zhǎng)
  private var mOffset:Float = 0.toFloat()// 默認(rèn)狀態(tài)下,mSelectorValue所在的位置 位于尺子總刻度的位置
  private var mLastX:Int = 0
  private var mMove: Int = 0
  private lateinit var mListener: OnValueChangeListener// 滑動(dòng)后數(shù)值回調(diào)

  private var mLineColor:Int= Color.GRAY //刻度的顏色
  private var mTextColor:Int= Color.BLACK//文字的顏色

  constructor(mContext: Context) : this(mContext,null)

  constructor(mContext: Context, attrs: AttributeSet?) : this(mContext, attrs!!,0)

  constructor(mContext: Context, attrs: AttributeSet,defStyleAttr:Int) : super(mContext, attrs,defStyleAttr) {
    init(mContext, attrs)
  }

  fun init(context: Context, attrs: AttributeSet){
    Log.d(TAG, "init")
    mScroller= Scroller(context)

    this.mLineSpaceWidth=myfloat(25.0f)
    this.mLineWidth=myfloat(2.0f)
    this.mLineMaxHeight=myfloat(100.0f)
    this.mLineMidHeight=myfloat(60.0f)
    this.mLineMinHeight=myfloat(40.0f)
    this.mTextHeight=myfloat(40.0f)

    val typedArray: TypedArray =context.obtainStyledAttributes(attrs,
        R.styleable.RulerView)

    mAlphaEnable= typedArray.getBoolean(R.styleable.RulerView_alphaEnable, mAlphaEnable)

    mLineSpaceWidth = typedArray.getDimension(R.styleable.RulerView_lineSpaceWidth, mLineSpaceWidth)
    mLineWidth = typedArray.getDimension(R.styleable.RulerView_lineWidth, mLineWidth)
    mLineMaxHeight = typedArray.getDimension(R.styleable.RulerView_lineMaxHeight, mLineMaxHeight)
    mLineMidHeight = typedArray.getDimension(R.styleable.RulerView_lineMidHeight, mLineMidHeight)
    mLineMinHeight = typedArray.getDimension(R.styleable.RulerView_lineMinHeight, mLineMinHeight)
    mLineColor = typedArray.getColor(R.styleable.RulerView_lineColor, mLineColor)

    mTextSize = typedArray.getDimension(R.styleable.RulerView_textSize, mTextSize)
    mTextColor = typedArray.getColor(R.styleable.RulerView_textColor, mTextColor)
    mTextMarginTop = typedArray.getDimension(R.styleable.RulerView_textMarginTop, mTextMarginTop)

    mSelectorValue = typedArray.getFloat(R.styleable.RulerView_selectorValue, 0.0f)
    mMinValue = typedArray.getFloat(R.styleable.RulerView_minValue, 0.0f)
    mMaxValue = typedArray.getFloat(R.styleable.RulerView_maxValue, 100.0f)
    mPerValue = typedArray.getFloat(R.styleable.RulerView_perValue, 0.1f)

    mMinVelocity= ViewConfiguration.get(getContext()).scaledMinimumFlingVelocity

    mTextPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    mTextPaint!!.textSize = mTextSize
    mTextPaint!!.color = mTextColor
    mTextHeight = getFontHeight(mTextPaint!!)

    mLinePaint = Paint(Paint.ANTI_ALIAS_FLAG)
    mLinePaint!!.strokeWidth = mLineWidth
    mLinePaint!!.color = mLineColor
  }

  private fun myfloat(paramFloat:Float):Float{
    return 0.5f+paramFloat*1.0f
  }

  private fun getFontHeight(paint: Paint):Float{
    val fm = paint.fontMetrics
    return fm.descent - fm.ascent
  }

  /**
   * 設(shè)置默認(rèn)的參數(shù)
   * @param selectorValue 未選擇時(shí) 默認(rèn)的值 滑動(dòng)后表示當(dāng)前中間指針正在指著的值
   * @param minValue  最大數(shù)值
   * @param maxValue  最小的數(shù)值
   * @param per  最小單位(如1:表示每2條刻度差為1;0.1:表示每2條刻度差為0.1;其中身高mPerValue為1,體重mPerValue 為0.1)
   */
  fun setValue(selectorValue: Float, minValue: Float, maxValue: Float, per: Float) {
    this.mSelectorValue = selectorValue
    this.mMaxValue = maxValue
    this.mMinValue = minValue
    this.mPerValue = per * 10.0f
    this.mTotalLine = ((mMaxValue * 10 - mMinValue * 10) / mPerValue).toInt() + 1


    mMaxOffset = (-(mTotalLine - 1) * mLineSpaceWidth).toInt()
    mOffset = (mMinValue - mSelectorValue) / mPerValue * mLineSpaceWidth * 10f
    Log.d(TAG, "mOffset:" + mOffset + ",mMaxOffset:" + mMaxOffset
        + ",mTotalLine:" + mTotalLine)
    invalidate()
    visibility = View.VISIBLE
  }

  fun setOnValueChangeListener(listener: OnValueChangeListener) {
    mListener = listener
  }

  override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {

    super.onSizeChanged(w, h, oldw, oldh)
    if (w > 0 && h > 0) {
      mWidth = w
      mHeight = h
    }
  }

  override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    var left: Float
    var height: Float
    var value: String
    var alpha = 0
    var scale: Float
    val srcPointX = mWidth / 2
    for (i in 0 until mTotalLine) {
      left = srcPointX.toFloat() + mOffset + i * mLineSpaceWidth

      if (left < 0 || left > mWidth) {
        continue //先畫默認(rèn)值在正中間,左右各一半的view。多余部分暫時(shí)不畫(也就是從默認(rèn)值在中間,畫旁邊左右的刻度線)
      }

      if (i % 10 == 0) {
        height = mLineMaxHeight
      } else if (i % 5 == 0) {
        height = mLineMidHeight
      } else {
        height = mLineMinHeight
      }
      if (mAlphaEnable) {
        scale = 1 - Math.abs(left - srcPointX) / srcPointX
        alpha = (255f * scale * scale).toInt()

        mLinePaint!!.setAlpha(alpha)
      }
      canvas.drawLine(left, 0f, left, height, mLinePaint)

      if (i % 10 == 0) {
        value = (mMinValue + i * mPerValue / 10).toInt().toString()
        if (mAlphaEnable) {
          mTextPaint!!.alpha = alpha
        }
        canvas.drawText(value, left - mTextPaint!!.measureText(value) / 2,
            height + mTextMarginTop + mTextHeight, mTextPaint)  // 在為整數(shù)時(shí),畫 數(shù)值
      }
    }
  }

  override fun onTouchEvent(event: MotionEvent): Boolean {
    Log.d(TAG, "onTouchEvent")

    val action = event.action
    val xPosition = event.x.toInt()

    if (mVelocityTracker == null) {
      mVelocityTracker = VelocityTracker.obtain()
    }
    mVelocityTracker!!.addMovement(event)

    when (action) {
      MotionEvent.ACTION_DOWN -> {
        mScroller!!.forceFinished(true)
        mLastX = xPosition
        mMove = 0
      }
      MotionEvent.ACTION_MOVE -> {
        mMove = mLastX - xPosition
        changeMoveAndValue()
      }
      MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
        countMoveEnd()
        countVelocityTracker()
        return false
      }
      else -> {
      }
    }

    mLastX = xPosition
    return true
  }

  private fun countVelocityTracker() {
    Log.d(TAG, "countVelocityTracker")
    mVelocityTracker!!.computeCurrentVelocity(1000) //初始化速率的單位
    val xVelocity = mVelocityTracker!!.xVelocity //當(dāng)前的速度
    if (Math.abs(xVelocity) > mMinVelocity) {
      mScroller!!.fling(0, 0, xVelocity.toInt(), 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0)
    }
  }

  /**
   * 滑動(dòng)結(jié)束后,若是指針在2條刻度之間時(shí),改變mOffset 讓指針正好在刻度上。
   */
  private fun countMoveEnd() {
    mOffset -= mMove.toFloat()
    if (mOffset <= mMaxOffset) {
      mOffset = mMaxOffset.toFloat()
    } else if (mOffset >= 0) {
      mOffset = 0f
    }

    mLastX = 0
    mMove = 0

    mSelectorValue = mMinValue + Math.round(Math.abs(mOffset) * 1.0f / mLineSpaceWidth) * mPerValue / 10.0f
    mOffset = (mMinValue - mSelectorValue) * 10.0f / mPerValue * mLineSpaceWidth

    notifyValueChange()
    postInvalidate()
  }

  /**
   * 滑動(dòng)后的操作
   */
  private fun changeMoveAndValue() {
    mOffset -= mMove.toFloat()

    if (mOffset <= mMaxOffset) {
      mOffset = mMaxOffset.toFloat()
      mMove = 0
      mScroller!!.forceFinished(true)
    } else if (mOffset >= 0) {
      mMove = 0
      mScroller!!.forceFinished(true)
    }
    mSelectorValue = mMinValue + Math.round(Math.abs(mOffset) * 1.0f / mLineSpaceWidth) * mPerValue / 10.0f


    notifyValueChange()
    postInvalidate()
  }

  private fun notifyValueChange() {
    if (null != mListener) {
      mListener.onValueChange(mSelectorValue)
    }
  }

  /**
   * 滑動(dòng)后的回調(diào)
   */
  interface OnValueChangeListener{
    fun onValueChange(value: Float)
  }

  override fun computeScroll() {
    Log.d(TAG, "computeScroll")
    super.computeScroll()
    if (mScroller!!.computeScrollOffset()) {//mScroller.computeScrollOffset()返回true表示滑動(dòng)還沒(méi)有結(jié)束
      if (mScroller!!.currX == mScroller!!.finalX) {
        countMoveEnd()
      } else {
        val xPosition = mScroller!!.currX
        mMove = mLastX - xPosition
        changeMoveAndValue()
        mLastX = xPosition
      }
    }
  }
}

在頁(yè)面中,我們要給自定義的標(biāo)尺設(shè)置默認(rèn)的參數(shù):未選擇時(shí)默認(rèn)的值、最大數(shù)值、最小的數(shù)值以及最小單位

//體重的view
    mWeightRuler!!.setOnValueChangeListener(object : RulerView.OnValueChangeListener {
      override fun onValueChange(value: Float) {
        weight = value
        mTvWeight!!.text = weight.toString() + "kg"
      }
    })
    mWeightRuler!!.setValue(55f, 20f, 200f, 0.1f)

以上是“Kotlin如何自定義View之標(biāo)尺控件”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI