麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 開發 > 綜合 > 正文

Kotlin自定義菜單控件

2024-07-21 23:03:48
字體:
來源:轉載
供稿:網友

本文實例為大家分享了Kotlin自定義菜單控件的具體代碼,供大家參考,具體內容如下

首先貼一下效果圖

Kotlin,菜單

思路:菜單控件分兩部分,一是點擊的子按鈕(RecordButton),二是包裹著子按鈕的容器(RecordMenu)。

子按鈕負責顯示文字及背景顏色和點擊事件,父容器主要控制子控件的位置和動畫顯示。

實現:

子按鈕,先貼代碼

class RecordButton : RelativeLayout { /** 控件顯示的文本*/ lateinit var textValue: String /** 控件顯示的文本字體大小*/ private var textSize: Float = 18f /** 控件顯示的文本字體顏色*/ private var textColor: Int = Color.BLACK /** 控件按下時顯示的文本字體顏色*/ private var textColorPress: Int = Color.WHITE /** 控件顯示的背景顏色*/ private var backColorNormal: Int = R.drawable.bg_menu_item /** 控件按下時顯示的背景顏色*/ private var backColorPress: Int = R.drawable.bg_menu_item_press /** 控件是否是主按鈕*/ var isSwitchMain: Boolean = false /** 按鈕按下時的時間*/ var pressBtnTime: Long = 0L /** 按鈕抬起時的時間*/ var upBtnTime: Long = 0L /** 事件是否是點擊事件*/ var isClick: Boolean = false /** 點擊事件是否打開*/ var isOpen: Boolean = false /** 文本控件*/ private lateinit var textView: TextView /** 監聽事件*/ var onRecordItemClickListener: OnRecordItemClickListener? = null  constructor(context: Context,    textValue: String,    textSize: Float,    textColor: Int,    backColorNormal: Int,    textColorPress: Int,    backColorPress: Int) : this(context) {  this.textValue = textValue  this.textSize = textSize  this.textColor = textColor  this.backColorNormal = backColorNormal  this.isSwitchMain = isSwitchMain  this.textColorPress = textColorPress  this.backColorPress = backColorPress  setBackgroundResource(backColorNormal)   textView = TextView(context)  textView.text = textValue  textView.gravity = CENTER  textView.setTextColor(textColor)  textView.textSize = textSize  var ll = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)  ll.addRule(CENTER_IN_PARENT)  addView(textView, ll) }  constructor(context: Context) : this(context, null) {  }  constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) { }  constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {  }  override fun onTouchEvent(event: MotionEvent?): Boolean {  when (event?.action) {   MotionEvent.ACTION_DOWN -> {    pressBtnTime = System.currentTimeMillis()    setBackgroundResource(backColorPress)    textView.setTextColor(textColorPress)    return true   }   MotionEvent.ACTION_MOVE -> {   }   MotionEvent.ACTION_UP -> {    upBtnTime = System.currentTimeMillis()    setBackgroundResource(backColorNormal)    textView.setTextColor(textColor)    isClick = (upBtnTime - pressBtnTime) / 1000 < 0.5   }  }  if (isClick) {   onRecordItemClickListener?.onClick(isSwitchMain, textValue,isOpen)   isOpen = !isOpen  }  return true }}

這里主要用一個RelativeLayout包裹著一個TextView,這么寫是為了防止以后擴展,需要添加圖片什么的,關于這個樣式和顯示沒什么好說的,主要的就是點擊事件,在觸摸事件中判斷按下和抬起的時間差,如果時間差小于0.5秒則斷定為點擊。

包裹容器

class RecordMenu : RelativeLayout{ /** 子按鈕半徑*/ private var itemRadius: Int = 0 /*** 按鈕間距*/ private var itemMargin: Int = 0 /** 動畫時間*/ private var duration: Long = 0 /** 字體大小*/ private var itemFontSize = 18f /** 字體正常顏色*/ private var itemFontColorN = Color.BLACK /** 點擊時字體顏色*/ private var itemFontColorP = Color.WHITE /** 按鈕正常背景*/ private var itemBackDrawableN = R.drawable.bg_menu_item /** 按鈕點擊背景*/ private var itemBackDrawableP = R.drawable.bg_menu_item_press /** 是否是展開狀態*/ private var isOpen: Boolean = false /** 動畫是否正在運行*/ private var isRun: Boolean = false /** 子控件監聽*/ private var recordListener = RecordListener() /** 上一級的監聽事件*/ var onRecordItemClickListener: OnRecordItemClickListener? = null  constructor(context: Context):this(context,null){  }  constructor(context: Context, attrs: AttributeSet?) : this(context,attrs,0) {  }  constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs,defStyleAttr) {  init(context, attrs) }  override fun onLayout(change: Boolean, l: Int, t: Int, r: Int, b: Int) {  /** 畫出每個子控件的位置*/  for (i in 0 until childCount) {   var recordButton = getChildAt(i) as RecordButton   var left: Int = 0   var right: Int = itemRadius * 2   var top: Int = (childCount - 1) * (itemRadius * 2 + itemMargin) + itemRadius   var bottom: Int = top + itemRadius * 2   recordButton.layout(left, top, right, bottom)   } }  override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {  var width = itemRadius * 2  var height = (childCount - 1) * (itemRadius * 2 + itemMargin) + itemRadius * 2 + itemRadius  width += paddingLeft + paddingRight  height += paddingTop + paddingBottom  val count = childCount  for (i in 0 until count) {   getChildAt(i).measure(width, width)   if(i == count-1){    var recordButton = getChildAt(i) as RecordButton    recordButton.isSwitchMain = true   }  }  setMeasuredDimension(width, height) }  private fun init(context: Context, attrs: AttributeSet?) {  val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RecordMenu)  itemRadius = typedArray.getDimension(R.styleable.RecordMenu_itemRadius, 30f).toInt()  itemMargin = typedArray.getDimension(R.styleable.RecordMenu_itemMargin, 10f).toInt()  duration = typedArray.getInteger(R.styleable.RecordMenu_animDuration, 2000).toLong()  itemFontSize = typedArray.getDimension(R.styleable.RecordMenu_itemFontSize,18f)  itemFontColorN = typedArray.getColor(R.styleable.RecordMenu_itemFontColorN,Color.BLACK)  itemFontColorP = typedArray.getColor(R.styleable.RecordMenu_itemFontColorP,Color.WHITE)  itemBackDrawableN = typedArray.getResourceId(R.styleable.RecordMenu_itemBackDrawableN,R.drawable.bg_menu_item)  itemBackDrawableP = typedArray.getResourceId(R.styleable.RecordMenu_itemBackDrawableP,R.drawable.bg_menu_item_press) }  fun addItemView(textValue: String){  var recordButton = RecordButton(context,textValue,itemFontSize,itemFontColorN,itemBackDrawableN,itemFontColorP,itemBackDrawableP)  var l1 = LayoutParams(itemRadius * 2, itemRadius * 2)  addView(recordButton, l1)  recordButton.onRecordItemClickListener = recordListener } fun addItemView(textValue: String,itemBackDrawableN:Int,itemBackDrawableP:Int){  var recordButton = RecordButton(context,textValue,itemFontSize,itemFontColorN,itemBackDrawableN,itemFontColorP,itemBackDrawableP)  var l1 = LayoutParams(itemRadius * 2, itemRadius * 2)  addView(recordButton, l1)  recordButton.onRecordItemClickListener = recordListener } inner class RecordListener : OnRecordItemClickListener {  override fun onClick(isSwitch: Boolean, textValue: String,isOpen1:Boolean) {   if (!isRun) {    if (!isOpen) {     openMenu()    } else {     closeMenu()    }   }   onRecordItemClickListener?.onClick(isSwitch,textValue,isOpen1)  } }  /**  * 展開控件  */ fun openMenu() {  isOpen = true  isRun = true  for (i in 0 until childCount) {   buttonItemOpenAnimation(i, getChildAt(i) as RecordButton)  } }  /**  * 關閉控件  */ fun closeMenu() {  isRun = true  isOpen = false  for (i in 0 until childCount) {   buttonItemCloseAnimation(i, getChildAt(i) as RecordButton)  } }  /**  * 展開動畫  */ private fun buttonItemOpenAnimation(index: Int, view: RecordButton) {  if (!view.isSwitchMain) {   val propertyAnimator = view.animate().alpha(1f).setInterpolator(OvershootInterpolator()).setDuration(duration / 3)   propertyAnimator.y((itemRadius * 2 * index + itemMargin * index + itemRadius).toFloat())   if (isOpen) {    view.visibility = View.VISIBLE   }    propertyAnimator.setListener(object : Animator.AnimatorListener {    override fun onAnimationRepeat(p0: Animator?) {     }     override fun onAnimationCancel(p0: Animator?) {     }     override fun onAnimationEnd(p0: Animator?) {     if (index == childCount - 2) {      isRun = false     }    }     override fun onAnimationStart(p0: Animator?) {     }   })   propertyAnimator.start()  } }  /**  * 關閉動畫  */ private fun buttonItemCloseAnimation(index: Int, view: RecordButton) {  if (!view.isSwitchMain) {   val propertyAnimator = view.animate().alpha(0f).setDuration(duration / 3)   propertyAnimator.y(((itemRadius * 2 + itemMargin) * (childCount - 1) + itemRadius).toFloat())     propertyAnimator.setListener(object : Animator.AnimatorListener {    override fun onAnimationStart(animation: Animator) {}     override fun onAnimationEnd(animation: Animator) {     if (index == childCount - 2) {      isRun = false     }     if (!isOpen) {      view.visibility = View.GONE     }    }     override fun onAnimationCancel(animation: Animator) {}     override fun onAnimationRepeat(animation: Animator) {}   })    propertyAnimator.start()  } }}

這里面主要就是控制子視圖的大小,位置,動畫。在onLayout方法中遍歷每個子視圖,通過layout設置視圖位置,這里設置每個子視圖都在容器的底部。然后在OnMeasure中設置整個視圖的大小,這個根據子視圖的大小和個數來計算同時加上內邊距。

最后就是通過子視圖的點擊事件來執行動畫,這里用到的是屬性動畫,用的是系統自帶的一個插值器OvershootInterpolator,這個插值器實現的效果就是在線性上先快速的到達終點然后超出然后仔慢慢回到終點,當然不想要這種效果自己可以自定義一個插值器。至于插值器如何用及如何自定義,這里就不在贅述,以后會專門寫一篇文章來介紹。

以上就是這個菜單控件的整體實現過程,是不是很簡單。


注:相關教程知識閱讀請移步到kotlin教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 成人在线免费看 | 免费a视频在线观看 | a级高清免费毛片av在线 | 男女羞羞在线观看 | 欧美精品免费一区二区三区 | 91福利免费视频 | 一级黄色性感片 | 麻豆视频网 | 看免费毛片 | 日本在线免费观看视频 | 成人一级免费视频 | 国产精品视频一区二区三区四区五区 | 成人不卡在线观看 | 久久国产精品系列 | 91精品国产乱码久久桃 | 日韩中文字幕一区二区三区 | 国产91一区二区三区 | 欧美一级毛片免费观看 | 把娇妻调教成暴露狂 | 曰韩毛片| 国产精品手机在线亚洲 | 欧美1区2区在线观看 | 草莓福利社区在线 | 午夜视频久久久 | 久久国产秒 | 国产成人精品一区二区三区电影 | 欧美人与性禽动交精品 | 免费观看国产精品视频 | 久久久久97国产精 | 欧美a视频 | 午夜免费网 | 成人啪啪18免费网站 | 免费99热在线观看 | 精品一区二区亚洲 | 色天使中文字幕 | 中文字幕一区久久 | 欧美成年人在线视频 | 成年人小视频在线观看 | 性欧美性欧美 | 欧洲成人av| 牛牛视频在线 |