您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
这篇文章将为大家详细讲解有关如何使用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() } } }
关于如何使用Kotlin自定义菜单控件就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。