ViewGroup.LayoutParams的FILL_PARENT与MATCH_PARENT两个常量

本文探讨了Android布局参数中MATCH_PARENT与FILL_PARENT的含义及其区别。指出这两个常量数值相同,均为-1(0xffffffff)。FILL_PARENT在API Level 8之后被标记为过时,并被MATCH_PARENT替代。
ViewGroup.LayoutParams的FILL_PARENT与MATCH_PARENT两个常量
 FILL_PARENT与MATCH_PARENT的数值相同

  Constant Value: -1 (0xffffffff)

  2.  FILL_PARENT在API里已注明:This value is deprecated starting in API Level 8 and replaced by MATCH_PARENT.

  3.一个是API8之前的一个是API8之后推荐的。

package com.example.bulbpage import android.annotation.SuppressLint import android.content.res.Resources import android.graphics.Outline import android.graphics.Path import android.graphics.drawable.ClipDrawable import android.graphics.drawable.ColorDrawable import android.graphics.drawable.LayerDrawable import android.os.Bundle import android.view.GestureDetector import android.view.Gravity import android.view.MotionEvent import android.view.View import android.view.ViewOutlineProvider import android.widget.FrameLayout import android.widget.ImageView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import com.example.bulbpage.databinding.ActivityMainBinding import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.button.MaterialButton class MainActivity : AppCompatActivity() { private var _binding: ActivityMainBinding? = null private val binding get() = _binding!! // ✅ 使用 by lazy 延迟初始化 private val colorOverlay: View by lazy { binding.colorOverlay } private lateinit var layerDrawable: LayerDrawable private lateinit var colorDrawable: ColorDrawable private var currentColorResId = R.color.white @SuppressLint("ClickableViewAccessibility") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) _binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) val llBottomSheet = binding.llBottomSheet val pullImageView = binding.pull colorOverlay.setBackgroundColor(ContextCompat.getColor(this, currentColorResId)) pullImageView.clipToOutline = true pullImageView.outlineProvider = object : ViewOutlineProvider() { override fun getOutline(view: View, outline: Outline) { val cornerRadius = 80f val path = Path() val width = view.width.toFloat() val height = view.height.toFloat() path.moveTo(0f, height) path.lineTo(0f, cornerRadius) path.quadTo(width / 2, 0f, width, cornerRadius) path.lineTo(width, height) path.close() outline.setConvexPath(path) } } //灯泡亮度操作 val lampImageView = binding.lampImageView var startY = 0f var totalDelta = 0f var isDragging = false // 是否已进入拖动状态 val maxDelta = 150 * resources.displayMetrics.density // 灯泡图高度 val gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { // 只有起点在 lampImageView 内部才开始检测滑动 if (e.x >= 0 && e.x <= lampImageView.width && e.y >= 0 && e.y <= lampImageView.height) { startY = e.y isDragging = true return true } isDragging = false return false } override fun onScroll( e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float ): Boolean { if (!isDragging) return false totalDelta += distanceY totalDelta = totalDelta.coerceIn(0f, maxDelta) val percent = (totalDelta / maxDelta) * 100 val level = (percent * 100).toInt() (binding.lampImageView.drawable as? ClipDrawable)?.level = level binding.percentText.text = "${percent.toInt()}%" // 设置遮罩层透明度:0% -> 50%, 100% -> 100% val alpha =0.4f * (1 - percent / 100f) binding.coverView.alpha = alpha return true } }) // 为 lampImageView 设置触摸监听器(处理 ACTION_UP) lampImageView.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { isDragging = false } } gestureDetector.onTouchEvent(event) } // 按钮组点击绑定 val buttons = listOf( binding.buttonAuto, binding.buttonWhite, binding.buttonOrange, binding.buttonDeepblue, binding.buttonSkyblue, binding.buttonFlamered ) buttons.forEach { button -> button.setOnClickListener { onButtonClicked(button) } } val behavior = BottomSheetBehavior.from(llBottomSheet) updatePullSelectorState(behavior.state) val gradientDrawable = ContextCompat.getDrawable(this, R.drawable.radial_gradient) ?: throw Resources.NotFoundException("radial_gradient.xml not found") colorDrawable = ColorDrawable(ContextCompat.getColor(this, currentColorResId)) val layers = arrayOf(gradientDrawable, colorDrawable) layerDrawable = LayerDrawable(layers) for (i in layers.indices) { layerDrawable.setLayerWidth(i, LayerDrawable.LayoutParams.MATCH_PARENT) layerDrawable.setLayerHeight(i, LayerDrawable.LayoutParams.MATCH_PARENT) layerDrawable.setLayerGravity(i, Gravity.FILL) } binding.colorOverlay.background = layerDrawable } //按钮组点击事件 // 声明 lastSelectedIcon 和 lastSelectedRing 用于记录上一个选中的图标和圆环 private var lastSelectedIcon: ImageView? = null private var lastSelectedRing: View? = null private fun onButtonClicked(button: MaterialButton) { when (button.id) { R.id.button_auto -> { currentColorResId = R.color.white clearSelection() } else -> { val container = button.parent as? FrameLayout ?: return val icon = when (button.id) { R.id.button_white -> binding.editiconWhite R.id.button_orange -> binding.editiconOrange R.id.button_deepblue -> binding.editiconDeepblue R.id.button_skyblue -> binding.editiconSkyblue R.id.button_flamered -> binding.editiconFlamered else -> null } val ring = when (button.id) { R.id.button_white -> binding.ringWhite R.id.button_orange -> binding.ringOrange R.id.button_deepblue -> binding.ringDeepblue R.id.button_skyblue -> binding.ringSkyblue R.id.button_flamered -> binding.ringFlamered else -> null } lastSelectedIcon?.visibility = View.GONE lastSelectedRing?.visibility = View.GONE icon?.visibility = View.VISIBLE ring?.visibility = View.VISIBLE lastSelectedIcon = icon lastSelectedRing = ring when (button.id) { R.id.button_white -> currentColorResId = R.color.white R.id.button_orange -> currentColorResId = R.color.orange R.id.button_deepblue -> currentColorResId = R.color.deepblue R.id.button_skyblue -> currentColorResId = R.color.skyblue R.id.button_flamered -> currentColorResId = R.color.flamered } } } // 更新颜色层 val newColor = ContextCompat.getColor(this, currentColorResId) colorDrawable.color = newColor binding.colorOverlay.background = layerDrawable } private fun clearSelection() { lastSelectedIcon?.visibility = View.GONE lastSelectedRing?.visibility = View.GONE lastSelectedIcon = null lastSelectedRing = null } private fun updatePullSelectorState(state: Int) { when (state) { BottomSheetBehavior.STATE_EXPANDED -> { binding.pull.isSelected = true } else -> { binding.pull.isSelected = false } } } override fun onDestroy() { super.onDestroy() _binding = null } } 标红:Unresolved reference 'LayoutParams'.
08-21
package com.super_rabbit.wheel_picker import android.content.Context import android.graphics.Canvas import android.graphics.Paint import android.graphics.Typeface import android.os.Build import android.util.AttributeSet import android.util.Log import android.view.* import android.view.animation.DecelerateInterpolator import android.widget.OverScroller import androidx.core.content.ContextCompat import java.util.* /** * Created by wanglu on 3/10/18. */ /** * Interface to listen for changes of the current value. */ interface OnValueChangeListener { /** * Called upon a change of the current value. * * @param picker The NumberPicker associated with this listener. * @param oldVal The previous value. * @param newVal The new value. */ fun onValueChange(picker: WheelPicker, oldVal: String, newVal: String) } interface OnScrollListener { /** * Callback invoked while the number picker scroll state has changed. * * @param view The view whose scroll state is being reported. * @param scrollState The current scroll state. One of * [.SCROLL_STATE_IDLE], * [.SCROLL_STATE_TOUCH_SCROLL] or * [.SCROLL_STATE_IDLE]. */ fun onScrollStateChange(view: WheelPicker, scrollState: Int) companion object { /** * The view is not scrolling. */ const val SCROLL_STATE_IDLE = 0 /** * The user is scrolling using touch, and his finger is still on the screen. */ const val SCROLL_STATE_TOUCH_SCROLL = 1 /** * The user had previously been scrolling using touch and performed a fling. */ const val SCROLL_STATE_FLING = 2 } } class WheelPicker @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { private val TOP_AND_BOTTOM_FADING_EDGE_STRENGTH = 0.9f private val SNAP_SCROLL_DURATION = 300 private val SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT = 4 private val DEFAULT_ITEM_COUNT = 3 private val DEFAULT_TEXT_SIZE = 80 private var mSelectorItemCount: Int private var mSelectorVisibleItemCount: Int private var mMinIndex: Int private var mMaxIndex: Int private var mMaxValidIndex: Int? = null private var mMinValidIndex: Int? = null private var mWheelMiddleItemIndex: Int private var mWheelVisibleItemMiddleIndex: Int private var mSelectorItemIndices: ArrayList<Int> private var mSelectorItemValidStatus: ArrayList<Boolean> private var mCurSelectedItemIndex = 0 private var mWrapSelectorWheelPreferred: Boolean private var mTextPaint: Paint = Paint() private var mSelectedTextColor: Int private var mUnSelectedTextColor: Int private var mTextSize: Int private var mTextAlign: String private var mOverScroller: OverScroller? = null private var mVelocityTracker: VelocityTracker? = null private val mTouchSlop: Int private val mMaximumVelocity: Int private val mMinimumVelocity: Int private var mLastY: Float = 0f private var mIsDragging: Boolean = false private var mCurrentFirstItemOffset: Int = 0 private var mInitialFirstItemOffset = Int.MIN_VALUE private var mTextGapHeight: Int = 0 private var mItemHeight: Int = 0 private var mTextHeight: Int = 0 private var mPreviousScrollerY: Int = 0 private var mOnValueChangeListener: OnValueChangeListener? = null private var mOnScrollListener: OnScrollListener? = null private var mAdapter: WheelAdapter? = null private var mFadingEdgeEnabled = true private var mSelectedTextScale = 0.3f private var mTypefaceIndex: Int = 0 /** * The current scroll state of the number picker. */ private var mScrollState = OnScrollListener.SCROLL_STATE_IDLE init { val attributesArray = context.obtainStyledAttributes(attrs, R.styleable.WheelPicker, defStyleAttr, 0) mSelectorItemCount = attributesArray.getInt(R.styleable.WheelPicker_wheelItemCount, DEFAULT_ITEM_COUNT) + 2 mWheelMiddleItemIndex = (mSelectorItemCount - 1) / 2 mSelectorVisibleItemCount = mSelectorItemCount - 2 mWheelVisibleItemMiddleIndex = (mSelectorVisibleItemCount - 1) / 2 mSelectorItemIndices = ArrayList(mSelectorItemCount) mSelectorItemValidStatus = ArrayList(mSelectorItemCount) mMinIndex = attributesArray.getInt(R.styleable.WheelPicker_min, Integer.MIN_VALUE) mMaxIndex = attributesArray.getInt(R.styleable.WheelPicker_max, Integer.MAX_VALUE) if (attributesArray.hasValue(R.styleable.WheelPicker_maxValidIndex)) mMaxValidIndex = attributesArray.getInt(R.styleable.WheelPicker_maxValidIndex, 0) if (attributesArray.hasValue(R.styleable.WheelPicker_minValidIndex)) mMinValidIndex = attributesArray.getInt(R.styleable.WheelPicker_minValidIndex, 0) mWrapSelectorWheelPreferred = attributesArray.getBoolean(R.styleable.WheelPicker_wrapSelectorWheel, false) mSelectedTextScale = attributesArray.getFloat(R.styleable.WheelPicker_selectedTextScale, 0.3f) mOverScroller = OverScroller(context, DecelerateInterpolator(2.5f)) val configuration = ViewConfiguration.get(context) mTouchSlop = configuration.scaledTouchSlop mMaximumVelocity = configuration.scaledMaximumFlingVelocity / SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT mMinimumVelocity = configuration.scaledMinimumFlingVelocity mSelectedTextColor = attributesArray.getColor( R.styleable.WheelPicker_selectedTextColor , ContextCompat.getColor(context, R.color.color_4_blue) ) mUnSelectedTextColor = attributesArray.getColor( R.styleable.WheelPicker_textColor , ContextCompat.getColor(context, R.color.color_3_dark_blue) ) mTextSize = attributesArray.getDimensionPixelSize(R.styleable.WheelPicker_textSize, DEFAULT_TEXT_SIZE) val textAlignInt = attributesArray.getInt(R.styleable.WheelPicker_align, 1) mTextAlign = when (textAlignInt) { 0 -> "LEFT" 1 -> "CENTER" 2 -> "RIGHT" else -> "CENTER" } mFadingEdgeEnabled = attributesArray.getBoolean(R.styleable.WheelPicker_fadingEdgeEnabled, true) mTypefaceIndex = attributesArray.getInt(R.styleable.WheelPicker_typeface, 0); mTextPaint.run { isAntiAlias = true isAntiAlias = true textSize = mTextSize.toFloat() textAlign = Paint.Align.valueOf(mTextAlign) style = Paint.Style.FILL_AND_STROKE typeface = when(mTypefaceIndex) { // for the constant values please check the WheelPicker_typeface in the attrs.xml 0 -> Typeface.DEFAULT 1 -> Typeface.SANS_SERIF 2 -> Typeface.SERIF else -> Typeface.DEFAULT } } attributesArray.recycle() initializeSelectorWheelIndices() } override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { super.onLayout(changed, left, top, right, bottom) if (changed) { // need to do all this when we know our size initializeSelectorWheel() initializeFadingEdges() } } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { // Try greedily to fit the max width and height. var lp: ViewGroup.LayoutParams? = layoutParams if (lp == null) lp = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) var width = calculateSize(suggestedMinimumWidth, lp.width, widthMeasureSpec) var height = calculateSize(suggestedMinimumHeight, lp.height, heightMeasureSpec) width += paddingLeft + paddingRight height += paddingTop + paddingBottom setMeasuredDimension(width, height) } override fun getSuggestedMinimumWidth(): Int { var suggested = super.getSuggestedMinimumHeight() if (mSelectorVisibleItemCount > 0) { suggested = Math.max(suggested, computeMaximumWidth()) } return suggested } override fun getSuggestedMinimumHeight(): Int { var suggested = super.getSuggestedMinimumWidth() if (mSelectorVisibleItemCount > 0) { val fontMetricsInt = mTextPaint.fontMetricsInt val height = fontMetricsInt.descent - fontMetricsInt.ascent suggested = Math.max(suggested, height * mSelectorVisibleItemCount) } return suggested } private fun computeMaximumWidth(): Int { mTextPaint.textSize = mTextSize * 1.3f if (mAdapter != null) { return if (!mAdapter!!.getTextWithMaximumLength().isEmpty()) { val suggestedWith = mTextPaint.measureText(mAdapter!!.getTextWithMaximumLength()).toInt() mTextPaint.textSize = mTextSize * 1.0f suggestedWith } else { val suggestedWith = mTextPaint.measureText("0000").toInt() mTextPaint.textSize = mTextSize * 1.0f suggestedWith } } val widthForMinIndex = mTextPaint.measureText(mMinIndex.toString()).toInt() val widthForMaxIndex = mTextPaint.measureText(mMaxIndex.toString()).toInt() mTextPaint.textSize = mTextSize * 1.0f return if (widthForMinIndex > widthForMaxIndex) widthForMinIndex else widthForMaxIndex } private fun calculateSize(suggestedSize: Int, paramSize: Int, measureSpec: Int): Int { var result = 0 val size = MeasureSpec.getSize(measureSpec) val mode = MeasureSpec.getMode(measureSpec) when (MeasureSpec.getMode(mode)) { MeasureSpec.AT_MOST -> if (paramSize == ViewGroup.LayoutParams.WRAP_CONTENT) result = Math.min(suggestedSize, size) else if (paramSize == ViewGroup.LayoutParams.MATCH_PARENT) result = size else { result = Math.min(paramSize, size) } MeasureSpec.EXACTLY -> result = size MeasureSpec.UNSPECIFIED -> result = if (paramSize == ViewGroup.LayoutParams.WRAP_CONTENT || paramSize == ViewGroup.LayoutParams .MATCH_PARENT ) suggestedSize else { paramSize } } return result } private fun initializeSelectorWheel() { mItemHeight = getItemHeight() mTextHeight = computeTextHeight() mTextGapHeight = getGapHeight() val visibleMiddleItemPos = mItemHeight * mWheelVisibleItemMiddleIndex + (mItemHeight + mTextHeight) / 2 mInitialFirstItemOffset = visibleMiddleItemPos - mItemHeight * mWheelMiddleItemIndex mCurrentFirstItemOffset = mInitialFirstItemOffset } private fun initializeFadingEdges() { isVerticalFadingEdgeEnabled = mFadingEdgeEnabled if (mFadingEdgeEnabled) setFadingEdgeLength((bottom - top - mTextSize) / 2) } private fun initializeSelectorWheelIndices() { mSelectorItemIndices.clear() mSelectorItemValidStatus.clear() mCurSelectedItemIndex = if (mMinValidIndex == null || mMinValidIndex!! < mMinIndex) { if (mMinIndex <= 0) { 0 } else { mMinIndex } } else { if (mMinValidIndex!! <= 0) { 0 } else { mMinValidIndex!! } } for (i in 0 until mSelectorItemCount) { var selectorIndex = mCurSelectedItemIndex + (i - mWheelMiddleItemIndex) if (mWrapSelectorWheelPreferred) { selectorIndex = getWrappedSelectorIndex(selectorIndex) } mSelectorItemIndices.add(selectorIndex) mSelectorItemValidStatus.add(isValidPosition(selectorIndex)) } } override fun getBottomFadingEdgeStrength(): Float { return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH } override fun getTopFadingEdgeStrength(): Float { return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) drawVertical(canvas) } override fun onTouchEvent(event: MotionEvent): Boolean { onTouchEventVertical(event) return true } private fun onTouchEventVertical(event: MotionEvent) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain() } mVelocityTracker?.addMovement(event) val action: Int = event.actionMasked when (action) { MotionEvent.ACTION_DOWN -> { if (!mOverScroller!!.isFinished) mOverScroller!!.forceFinished(true) mLastY = event.y } MotionEvent.ACTION_MOVE -> { var deltaY = event.y - mLastY if (!mIsDragging && Math.abs(deltaY) > mTouchSlop) { parent?.requestDisallowInterceptTouchEvent(true) if (deltaY > 0) { deltaY -= mTouchSlop } else { deltaY += mTouchSlop } onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) mIsDragging = true } if (mIsDragging) { scrollBy(0, deltaY.toInt()) invalidate() mLastY = event.y } } MotionEvent.ACTION_UP -> { if (mIsDragging) { mIsDragging = false parent?.requestDisallowInterceptTouchEvent(false) mVelocityTracker?.computeCurrentVelocity(1000, mMaximumVelocity.toFloat()) val velocity = mVelocityTracker?.yVelocity?.toInt() if (Math.abs(velocity!!) > mMinimumVelocity) { mPreviousScrollerY = 0 mOverScroller?.fling( scrollX, scrollY, 0, velocity, 0, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, (getItemHeight() * 0.7).toInt() ) invalidateOnAnimation() onScrollStateChange(OnScrollListener.SCROLL_STATE_FLING) } recyclerVelocityTracker() } else { //click event val y = event.y.toInt() handlerClickVertical(y) } } MotionEvent.ACTION_CANCEL -> { if (mIsDragging) { mIsDragging = false } recyclerVelocityTracker() } } } private fun handlerClickVertical(y: Int) { val selectorIndexOffset = y / mItemHeight - mWheelVisibleItemMiddleIndex changeValueBySteps(selectorIndexOffset) } override fun scrollBy(x: Int, y: Int) { if (y == 0) return val gap = mTextGapHeight if (!mWrapSelectorWheelPreferred && y > 0 && (mSelectorItemIndices[mWheelMiddleItemIndex] <= mMinIndex || (mMinValidIndex != null && mSelectorItemIndices[mWheelMiddleItemIndex] <= mMinValidIndex!!)) ) { if (mCurrentFirstItemOffset + y - mInitialFirstItemOffset < gap / 2) mCurrentFirstItemOffset += y else { mCurrentFirstItemOffset = mInitialFirstItemOffset + (gap / 2) if (!mOverScroller!!.isFinished && !mIsDragging) { mOverScroller!!.abortAnimation() } } return } if (!mWrapSelectorWheelPreferred && y < 0 && (mSelectorItemIndices[mWheelMiddleItemIndex] >= mMaxIndex || (mMaxValidIndex != null && mSelectorItemIndices[mWheelMiddleItemIndex] >= mMaxValidIndex!!)) ) { if (mCurrentFirstItemOffset + y - mInitialFirstItemOffset > -(gap / 2)) mCurrentFirstItemOffset += y else { mCurrentFirstItemOffset = mInitialFirstItemOffset - (gap / 2) if (!mOverScroller!!.isFinished && !mIsDragging) { mOverScroller!!.abortAnimation() } } return } mCurrentFirstItemOffset += y while (mCurrentFirstItemOffset - mInitialFirstItemOffset < -gap) { mCurrentFirstItemOffset += mItemHeight increaseSelectorsIndex() if (!mWrapSelectorWheelPreferred && (mSelectorItemIndices[mWheelMiddleItemIndex] >= mMaxIndex || (mMaxValidIndex != null && mSelectorItemIndices[mWheelMiddleItemIndex] >= mMaxValidIndex!!)) ) { mCurrentFirstItemOffset = mInitialFirstItemOffset } } while (mCurrentFirstItemOffset - mInitialFirstItemOffset > gap) { mCurrentFirstItemOffset -= mItemHeight decreaseSelectorsIndex() if (!mWrapSelectorWheelPreferred && (mSelectorItemIndices[mWheelMiddleItemIndex] <= mMinIndex || (mMinValidIndex != null && mSelectorItemIndices[mWheelMiddleItemIndex] <= mMinValidIndex!!)) ) { mCurrentFirstItemOffset = mInitialFirstItemOffset } } onSelectionChanged(mSelectorItemIndices[mWheelMiddleItemIndex], true) } override fun computeScroll() { super.computeScroll() if (mOverScroller!!.computeScrollOffset()) { val x = mOverScroller!!.currX val y = mOverScroller!!.currY if (mPreviousScrollerY == 0) { mPreviousScrollerY = mOverScroller!!.startY } scrollBy(x, y - mPreviousScrollerY) mPreviousScrollerY = y invalidate() } else { if (!mIsDragging) //align item adjustItemVertical() } } private fun adjustItemVertical() { mPreviousScrollerY = 0 var deltaY = mInitialFirstItemOffset - mCurrentFirstItemOffset if (Math.abs(deltaY) > mItemHeight / 2) { deltaY += if (deltaY > 0) -mItemHeight else mItemHeight } if (deltaY != 0) { mOverScroller!!.startScroll(scrollX, scrollY, 0, deltaY, 800) invalidateOnAnimation() } onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE) } private fun recyclerVelocityTracker() { mVelocityTracker?.recycle() mVelocityTracker = null } override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) { super.onScrollChanged(l, t, oldl, oldt) } private fun onScrollStateChange(scrollState: Int) { if (mScrollState == scrollState) { return } mScrollState = scrollState mOnScrollListener?.onScrollStateChange(this, scrollState) } private fun getItemHeight(): Int { return height / (mSelectorItemCount - 2) } private fun getGapHeight(): Int { return getItemHeight() - computeTextHeight() } private fun computeTextHeight(): Int { val metricsInt = mTextPaint.fontMetricsInt return Math.abs(metricsInt.bottom + metricsInt.top) } private fun invalidateOnAnimation() { if (Build.VERSION.SDK_INT >= 16) postInvalidateOnAnimation() else invalidate() } private fun drawVertical(canvas: Canvas) { if (mSelectorItemIndices.size == 0) return val itemHeight = getItemHeight() val x = when (mTextPaint.textAlign) { Paint.Align.LEFT -> paddingLeft.toFloat() Paint.Align.CENTER -> ((right - left) / 2).toFloat() Paint.Align.RIGHT -> (right - left).toFloat() - paddingRight.toFloat() else -> ((right - left) / 2).toFloat() } var y = mCurrentFirstItemOffset.toFloat() var i = 0 val topIndexDiffToMid = mWheelVisibleItemMiddleIndex val bottomIndexDiffToMid = mSelectorVisibleItemCount - mWheelVisibleItemMiddleIndex - 1 val maxIndexDiffToMid = Math.max(topIndexDiffToMid, bottomIndexDiffToMid) while (i < mSelectorItemIndices.size) { var scale = 1f val offsetToMiddle = Math.abs(y - (mInitialFirstItemOffset + mWheelMiddleItemIndex * itemHeight).toFloat()) if (maxIndexDiffToMid != 0) scale = mSelectedTextScale * (itemHeight * maxIndexDiffToMid - offsetToMiddle) / (itemHeight * maxIndexDiffToMid) + 1 if (mSelectorItemValidStatus[i]) { if (offsetToMiddle < mItemHeight / 2) { mTextPaint.color = mSelectedTextColor } else { mTextPaint.color = mUnSelectedTextColor } } else { mTextPaint.color = ContextCompat.getColor(context, R.color.material_grey_300) } canvas.save() canvas.scale(scale, scale, x, y) canvas.drawText(getValue(mSelectorItemIndices[i]), x, y, mTextPaint) canvas.restore() y += itemHeight i++ } } private fun getPosition(value: String): Int = when { mAdapter != null -> { validatePosition(mAdapter!!.getPosition(value)) } else -> try { val position = value.toInt() validatePosition(position) } catch (e: NumberFormatException) { 0 } } private fun increaseSelectorsIndex() { for (i in 0 until (mSelectorItemIndices.size - 1)) { mSelectorItemIndices[i] = mSelectorItemIndices[i + 1] mSelectorItemValidStatus[i] = mSelectorItemValidStatus[i + 1] } var nextScrollSelectorIndex = mSelectorItemIndices[mSelectorItemIndices.size - 2] + 1 if (mWrapSelectorWheelPreferred && nextScrollSelectorIndex > mMaxIndex) { nextScrollSelectorIndex = mMinIndex } mSelectorItemIndices[mSelectorItemIndices.size - 1] = nextScrollSelectorIndex mSelectorItemValidStatus[mSelectorItemIndices.size - 1] = isValidPosition(nextScrollSelectorIndex) } private fun decreaseSelectorsIndex() { for (i in mSelectorItemIndices.size - 1 downTo 1) { mSelectorItemIndices[i] = mSelectorItemIndices[i - 1] mSelectorItemValidStatus[i] = mSelectorItemValidStatus[i - 1] } var nextScrollSelectorIndex = mSelectorItemIndices[1] - 1 if (mWrapSelectorWheelPreferred && nextScrollSelectorIndex < mMinIndex) { nextScrollSelectorIndex = mMaxIndex } mSelectorItemIndices[0] = nextScrollSelectorIndex mSelectorItemValidStatus[0] = isValidPosition(nextScrollSelectorIndex) } private fun changeValueBySteps(steps: Int) { mPreviousScrollerY = 0 mOverScroller!!.startScroll(0, 0, 0, -mItemHeight * steps, SNAP_SCROLL_DURATION) invalidate() } private fun onSelectionChanged(current: Int, notifyChange: Boolean) { val previous = mCurSelectedItemIndex mCurSelectedItemIndex = current if (notifyChange && previous != current) { notifyChange(previous, current) } } private fun getWrappedSelectorIndex(selectorIndex: Int): Int { if (selectorIndex > mMaxIndex) { return mMinIndex + (selectorIndex - mMaxIndex) % (mMaxIndex - mMinIndex + 1) - 1 } else if (selectorIndex < mMinIndex) { return mMaxIndex - (mMinIndex - selectorIndex) % (mMaxIndex - mMinIndex + 1) + 1 } return selectorIndex } private fun notifyChange(previous: Int, current: Int) { mOnValueChangeListener?.onValueChange(this, getValue(previous), getValue(current)) } private fun validatePosition(position: Int): Int { return if (!mWrapSelectorWheelPreferred) { when { mMaxValidIndex == null && position > mMaxIndex -> mMaxIndex mMaxValidIndex != null && position > mMaxValidIndex!! -> mMaxValidIndex!! mMinValidIndex == null && position < mMinIndex -> mMinIndex mMinValidIndex != null && position < mMinValidIndex!! -> mMinValidIndex!! else -> position } } else { getWrappedSelectorIndex(position) } } fun scrollTo(position: Int) { if (mCurSelectedItemIndex == position) return mCurSelectedItemIndex = position mSelectorItemIndices.clear() for (i in 0 until mSelectorItemCount) { var selectorIndex = mCurSelectedItemIndex + (i - mWheelMiddleItemIndex) if (mWrapSelectorWheelPreferred) { selectorIndex = getWrappedSelectorIndex(selectorIndex) } mSelectorItemIndices.add(selectorIndex) } invalidate() } fun setOnValueChangedListener(onValueChangeListener: OnValueChangeListener) { mOnValueChangeListener = onValueChangeListener } fun setOnScrollListener(onScrollListener: OnScrollListener) { mOnScrollListener = onScrollListener } fun smoothScrollTo(position: Int) { val realPosition = validatePosition(position) changeValueBySteps(realPosition - mCurSelectedItemIndex) } fun smoothScrollToValue(value: String) { smoothScrollTo(getPosition(value)) } fun scrollToValue(value: String) { scrollTo(getPosition(value)) } fun setUnselectedTextColor(resourceId: Int) { mUnSelectedTextColor = resourceId } /** * Set user define adapter * * @adapter user define adapter * @indexRangeBasedOnAdapterSize specific if the picker's min~max range is based on adapter's size */ fun setAdapter(adapter: WheelAdapter?, indexRangeBasedOnAdapterSize: Boolean = true) { mAdapter = adapter if (mAdapter == null) { initializeSelectorWheelIndices() invalidate() return } if (adapter!!.getSize() != -1 && indexRangeBasedOnAdapterSize) { mMaxIndex = adapter.getSize() - 1 mMinIndex = 0 } mMaxValidIndex = adapter.getMaxValidIndex() mMinValidIndex = adapter.getMinValidIndex() initializeSelectorWheelIndices() invalidate() mAdapter?.picker = this } /** * Set a custom typeface object for the text * * @param typeface the custom typeface object */ fun setTypeface(typeface: Typeface) { mTextPaint.typeface = typeface } /** * Sets whether the selector wheel shown during flinging/scrolling should * wrap around the {@link NumberPicker#getMinValue()} and * {@link NumberPicker#getMaxValue()} values. * <p> * By default if the range (max - min) is more than the number of items shown * on the selector wheel the selector wheel wrapping is enabled. * </p> * <p> * <strong>Note:</strong> If the number of items, i.e. the range ( * {@link #getMaxValue()} - {@link #getMinValue()}) is less than * the number of items shown on the selector wheel, the selector wheel will * not wrap. Hence, in such a case calling this method is a NOP. * </p> * * @param wrapSelectorWheel Whether to wrap. */ fun setWrapSelectorWheel(wrap: Boolean) { mWrapSelectorWheelPreferred = wrap invalidate() } /** * Gets whether the selector wheel wraps when reaching the min/max value. * * @return True if the selector wheel wraps. * * @see .getMinValue * @see .getMaxValue */ fun getWrapSelectorWheel(): Boolean { return mWrapSelectorWheelPreferred } /** * Set how many visible item show in the picker */ fun setWheelItemCount(count: Int) { mSelectorItemCount = count + 2 mWheelMiddleItemIndex = (mSelectorItemCount - 1) / 2 mSelectorVisibleItemCount = mSelectorItemCount - 2 mWheelVisibleItemMiddleIndex = (mSelectorVisibleItemCount - 1) / 2 mSelectorItemIndices = ArrayList(mSelectorItemCount) mSelectorItemValidStatus = ArrayList(mSelectorItemCount) reset() invalidate() } /** * Set color for current selected item */ fun setSelectedTextColor(colorId: Int) { mSelectedTextColor = ContextCompat.getColor(context, colorId) invalidate() } fun getValue(position: Int): String = when { mAdapter != null -> mAdapter!!.getValue(position) else -> if (!mWrapSelectorWheelPreferred) { when { position > mMaxIndex -> "" position < mMinIndex -> "" else -> position.toString() } } else { getWrappedSelectorIndex(position).toString() } } fun setValue(value: String) { scrollToValue(value) } fun setMaxValue(max: Int) { mMaxIndex = max } fun getMaxValue(): String { return if (mAdapter != null) { mAdapter!!.getValue(mMaxIndex) } else { mMaxIndex.toString() } } fun setMinValue(min: Int) { mMinIndex = min } fun setMinValidValue(minValid: Int?) { mMinValidIndex = minValid } fun setMaxValidValue(maxValid: Int?) { mMaxValidIndex = maxValid } fun getMinValue(): String { return if (mAdapter != null) { mAdapter!!.getValue(mMinIndex) } else { mMinIndex.toString() } } fun reset() { initializeSelectorWheelIndices() initializeSelectorWheel() invalidate() } fun getCurrentItem(): String { return getValue(mCurSelectedItemIndex) } fun isValidPosition(position: Int): Boolean { return when { mMinValidIndex != null && position < mMinValidIndex!! -> false mMaxValidIndex != null && position > mMaxValidIndex!! -> false else -> true } } } internal fun Int.clamp(min: Int, max: Int): Int { if (this < min) return min return if (this > max) max else this }
10-29
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值