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

Kotlin自定義菜單控件

 更新時(shí)間:2018年07月27日 11:04:46   作者:android_hdh  
這篇文章主要為大家詳細(xì)介紹了Kotlin自定義菜單控件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

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

首先貼一下效果圖

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

子按鈕負(fù)責(zé)顯示文字及背景顏色和點(diǎn)擊事件,父容器主要控制子控件的位置和動(dòng)畫(huà)顯示。

實(shí)現(xiàn):

子按鈕,先貼代碼

class RecordButton : RelativeLayout {
 /** 控件顯示的文本*/
 lateinit var textValue: String
 /** 控件顯示的文本字體大小*/
 private var textSize: Float = 18f
 /** 控件顯示的文本字體顏色*/
 private var textColor: Int = Color.BLACK
 /** 控件按下時(shí)顯示的文本字體顏色*/
 private var textColorPress: Int = Color.WHITE
 /** 控件顯示的背景顏色*/
 private var backColorNormal: Int = R.drawable.bg_menu_item
 /** 控件按下時(shí)顯示的背景顏色*/
 private var backColorPress: Int = R.drawable.bg_menu_item_press
 /** 控件是否是主按鈕*/
 var isSwitchMain: Boolean = false
 /** 按鈕按下時(shí)的時(shí)間*/
 var pressBtnTime: Long = 0L
 /** 按鈕抬起時(shí)的時(shí)間*/
 var upBtnTime: Long = 0L
 /** 事件是否是點(diǎn)擊事件*/
 var isClick: Boolean = false
 /** 點(diǎn)擊事件是否打開(kāi)*/
 var isOpen: Boolean = false
 /** 文本控件*/
 private lateinit var textView: TextView
 /** 監(jiān)聽(tīng)事件*/
 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
 }
}

這里主要用一個(gè)RelativeLayout包裹著一個(gè)TextView,這么寫(xiě)是為了防止以后擴(kuò)展,需要添加圖片什么的,關(guān)于這個(gè)樣式和顯示沒(méi)什么好說(shuō)的,主要的就是點(diǎn)擊事件,在觸摸事件中判斷按下和抬起的時(shí)間差,如果時(shí)間差小于0.5秒則斷定為點(diǎn)擊。

包裹容器

class RecordMenu : RelativeLayout{
 /** 子按鈕半徑*/
 private var itemRadius: Int = 0
 /*** 按鈕間距*/
 private var itemMargin: Int = 0
 /** 動(dòng)畫(huà)時(shí)間*/
 private var duration: Long = 0
 /** 字體大小*/
 private var itemFontSize = 18f
 /** 字體正常顏色*/
 private var itemFontColorN = Color.BLACK
 /** 點(diǎn)擊時(shí)字體顏色*/
 private var itemFontColorP = Color.WHITE
 /** 按鈕正常背景*/
 private var itemBackDrawableN = R.drawable.bg_menu_item
 /** 按鈕點(diǎn)擊背景*/
 private var itemBackDrawableP = R.drawable.bg_menu_item_press
 /** 是否是展開(kāi)狀態(tài)*/
 private var isOpen: Boolean = false
 /** 動(dòng)畫(huà)是否正在運(yùn)行*/
 private var isRun: Boolean = false
 /** 子控件監(jiān)聽(tīng)*/
 private var recordListener = RecordListener()
 /** 上一級(jí)的監(jiān)聽(tīng)事件*/
 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) {
  /** 畫(huà)出每個(gè)子控件的位置*/
  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)
  }
 }
 
 /**
  * 展開(kāi)控件
  */
 fun openMenu() {
  isOpen = true
  isRun = true
  for (i in 0 until childCount) {
   buttonItemOpenAnimation(i, getChildAt(i) as RecordButton)
  }
 }
 
 /**
  * 關(guān)閉控件
  */
 fun closeMenu() {
  isRun = true
  isOpen = false
  for (i in 0 until childCount) {
   buttonItemCloseAnimation(i, getChildAt(i) as RecordButton)
  }
 }
 
 /**
  * 展開(kāi)動(dòng)畫(huà)
  */
 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()
  }
 }
 
 /**
  * 關(guān)閉動(dòng)畫(huà)
  */
 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()
  }
 }
}

這里面主要就是控制子視圖的大小,位置,動(dòng)畫(huà)。在onLayout方法中遍歷每個(gè)子視圖,通過(guò)layout設(shè)置視圖位置,這里設(shè)置每個(gè)子視圖都在容器的底部。然后在OnMeasure中設(shè)置整個(gè)視圖的大小,這個(gè)根據(jù)子視圖的大小和個(gè)數(shù)來(lái)計(jì)算同時(shí)加上內(nèi)邊距。

最后就是通過(guò)子視圖的點(diǎn)擊事件來(lái)執(zhí)行動(dòng)畫(huà),這里用到的是屬性動(dòng)畫(huà),用的是系統(tǒng)自帶的一個(gè)插值器OvershootInterpolator,這個(gè)插值器實(shí)現(xiàn)的效果就是在線性上先快速的到達(dá)終點(diǎn)然后超出然后仔慢慢回到終點(diǎn),當(dāng)然不想要這種效果自己可以自定義一個(gè)插值器。至于插值器如何用及如何自定義,這里就不在贅述,以后會(huì)專門寫(xiě)一篇文章來(lái)介紹。

以上就是這個(gè)菜單控件的整體實(shí)現(xiàn)過(guò)程,是不是很簡(jiǎn)單。

相關(guān)文章

最新評(píng)論