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

首頁 > 開發 > 綜合 > 正文

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教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 建平县| 松溪县| 晋江市| 苍山县| 安龙县| 沙田区| 安化县| 曲阜市| 海伦市| 山丹县| 章丘市| 霍林郭勒市| 肥东县| 稻城县| 兰西县| 剑阁县| 祁东县| 望城县| 巴彦淖尔市| 大同县| 龙门县| 尉犁县| 宜宾市| 太仓市| 上蔡县| 虞城县| 马公市| 宣化县| 额尔古纳市| 松溪县| 观塘区| 甘肃省| 秦皇岛市| 福州市| 临沧市| 即墨市| 郎溪县| 梧州市| 星座| 哈巴河县| 澎湖县|