可自动换行的RadioGroup
2017-06-15 15:57
411 查看
主要重写了onMeasure和onLayout
import android.content.Context import android.content.res.TypedArray import android.support.annotation.IdRes import android.util.AttributeSet import android.view.View import android.view.ViewGroup import android.widget.CompoundButton import android.widget.LinearLayout import android.widget.RadioButton import java.util.concurrent.atomic.AtomicInteger open class MultiRadioGroup : LinearLayout { var columnCount = 3//写到属性中 var checkedRadioButtonId = -1 @get:IdRes private var mChildOnCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null private var mProtectFromCheckedChange = false private var mOnCheckedChangeListener: OnCheckedChangeListener? = null private var mPassThroughListener: PassThroughHierarchyChangeListener? = null constructor(context: Context) : super(context) { orientation = LinearLayout.VERTICAL init() } constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { init() } private fun init() { mChildOnCheckedChangeListener = CheckedStateTracker() mPassThroughListener = PassThroughHierarchyChangeListener() super.setOnHierarchyChangeListener(mPassThroughListener) } override fun setOnHierarchyChangeListener(listener: ViewGroup.OnHierarchyChangeListener) { // the user listener is delegated to our pass-through listener mPassThroughListener!!.mOnHierarchyChangeListener = listener } override fun onFinishInflate() { super.onFinishInflate() // checks the appropriate radio button as requested in the XML file if (checkedRadioButtonId != -1) { mProtectFromCheckedChange = true setCheckedStateForView(checkedRadioButtonId, true) mProtectFromCheckedChange = false setCheckedId(checkedRadioButtonId) } } override fun addView(child: View, index: Int, params: ViewGroup.LayoutParams) { if (child is RadioButton) { val button = child if (button.isChecked) { mProtectFromCheckedChange = true if (checkedRadioButtonId != -1) { setCheckedStateForView(checkedRadioButtonId, false) } mProtectFromCheckedChange = false setCheckedId(button.id) } } super.addView(child, index, params) } fun check(@IdRes id: Int) { // don't even bother if (id != -1 && id == checkedRadioButtonId) { return } if (checkedRadioButtonId != -1) { setCheckedStateForView(checkedRadioButtonId, false) } if (id != -1) { setCheckedStateForView(id, true) } setCheckedId(id) } private fun setCheckedId(@IdRes id: Int) { checkedRadioButtonId = id if (mOnCheckedChangeListener != null) { mOnCheckedChangeListener!!.onCheckedChanged(this, checkedRadioButtonId) } } private fun setCheckedStateForView(viewId: Int, checked: Boolean) { val checkedView = findViewById(viewId) if (checkedView != null && checkedView is RadioButton) { checkedView.isChecked = checked } } fun clearCheck() { check(-1) } fun setOnCheckedChangeListener(listener: OnCheckedChangeListener) { mOnCheckedChangeListener = listener } override fun generateLayoutParams(attrs: AttributeSet): LayoutParams { return MultiRadioGroup.LayoutParams(context, attrs) } override fun checkLayoutParams(p: ViewGroup.LayoutParams): Boolean { return p is MultiRadioGroup.LayoutParams } override fun generateDefaultLayoutParams(): LinearLayout.LayoutParams { return LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT) } override fun getAccessibilityClassName(): CharSequence { return MultiRadioGroup::class.java.name } class LayoutParams : LinearLayout.LayoutParams { constructor(c: Context, attrs: AttributeSet) : super(c, attrs) {} constructor(w: Int, h: Int) : super(w, h) {} constructor(w: Int, h: Int, initWeight: Float) : super(w, h, initWeight) {} constructor(p: ViewGroup.LayoutParams) : super(p) {} constructor(source: ViewGroup.MarginLayoutParams) : super(source) {} override fun setBaseAttributes(a: TypedArray, widthAttr: Int, heightAttr: Int) { if (a.hasValue(widthAttr)) { width = a.getLayoutDimension(widthAttr, "layout_width") } else { width = ViewGroup.LayoutParams.WRAP_CONTENT } if (a.hasValue(heightAttr)) { height = a.getLayoutDimension(heightAttr, "layout_height") } else { height = ViewGroup.LayoutParams.WRAP_CONTENT } } } interface OnCheckedChangeListener { fun onCheckedChanged(group: MultiRadioGroup, @IdRes checkedId: Int) } private inner class CheckedStateTracker : CompoundButton.OnCheckedChangeListener { override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) { // prevents from infinite recursion if (mProtectFromCheckedChange) { return } mProtectFromCheckedChange = true if (checkedRadioButtonId != -1) { setCheckedStateForView(checkedRadioButtonId, false) } mProtectFromCheckedChange = false val id = buttonView.id setCheckedId(id) } } private inner class PassThroughHierarchyChangeListener : ViewGroup.OnHierarchyChangeListener { var mOnHierarchyChangeListener: ViewGroup.OnHierarchyChangeListener? = null override fun onChildViewAdded(parent: View, child: View) { if (parent === this@MultiRadioGroup && child is RadioButton) { var id = child.getId() // generates an id if it's missing if (id == View.NO_ID) { id = generateId() child.setId(id) } var clazz = CompoundButton::class.java var method = clazz.getDeclaredMethod("setOnCheckedChangeWidgetListener", CompoundButton.OnCheckedChangeListener::class.java) method.isAccessible = true method.invoke(child, mChildOnCheckedChangeListener) } mOnHierarchyChangeListener?.onChildViewAdded(parent, child) } override fun onChildViewRemoved(parent: View, child: View) { if (parent === this@MultiRadioGroup && child is RadioButton) { var clazz = CompoundButton::class.java var method = clazz.getDeclaredMethod("setOnCheckedChangeWidgetListener", CompoundButton.OnCheckedChangeListener::class.java) method.isAccessible = true method.invoke(child, null) } mOnHierarchyChangeListener?.onChildViewRemoved(parent, child) } } private val nextGeneratedId = AtomicInteger(1) fun generateId(): Int { while (true) { val result = nextGeneratedId.get() var newValue = result + 1 if (newValue > 0x00FFFFFF) newValue = 1 // Roll over to 1, not 0. if (nextGeneratedId.compareAndSet(result, newValue)) { return result } } } override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { layoutHorizontal(l, t, r, b) } private fun setChildFrame(child: View, left: Int, top: Int, width: Int, height: Int) { child.layout(left, top, left + width, top + height) } internal fun layoutHorizontal(left: Int, top: Int, right: Int, bottom: Int) { val paddingTop = paddingTop var childTop: Int var childLeft: Int val count = childCount childLeft = paddingLeft childTop = paddingTop var start = 0 var dir = 1 var i = 0 while (i < count) { val childIndex = start + dir * i val child = getChildAt(childIndex) if (child == null) { childLeft += 0 } else if (child!!.visibility != View.GONE) { val childHeight = child!!.measuredHeight val lp = child!!.layoutParams as Mul 4000 tiRadioGroup.LayoutParams val childWidth = (measuredWidth - columnCount * (lp.leftMargin + lp.rightMargin)) / columnCount child.measure(childWidth, childHeight) if (i > 0 && i % columnCount == 0) { childLeft = paddingLeft childTop += lp.topMargin childTop += childHeight + lp.bottomMargin } childLeft += lp.leftMargin setChildFrame(child, childLeft, childTop, childWidth, childHeight) childLeft += childWidth + lp.rightMargin i += 0 } i++ } } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) var i = 0 var height = paddingTop while (i < childCount) { if (i % columnCount == 0) { val childIndex = i val child = getChildAt(childIndex) val childHeight = child!!.measuredHeight val lp = child!!.layoutParams as MultiRadioGroup.LayoutParams height += lp.topMargin height += childHeight + lp.bottomMargin } i++ } setMeasuredDimension(measuredWidth, height) } }
相关文章推荐
- 可以自动换行的radioGroup
- RadioGroup 自动换行且保留点击事件
- Android开发之自动换行RadioGroup
- 筛选菜单--弹性式RadioGroup(可自动换行)
- 可自动换行的RadioGroup
- QCheckBox/QRadioButton 自动换行问题
- android之自定义ViewGroup和自动换行的布局的实现
- Android 可自动换行的单选 RadioGroupEx
- Android自定义ViewGroup自动换行实现滑动任意布局及事件处理效果
- 自定义ViewGroup实现控件自动换行
- 安卓开发listview中包含radiogroup选项在滚动时自动选中的解决方法。BaseAdapter,RadioGroup,ListView,ViewHolder
- Android RadioGroup 换行, 支持多行多列
- Android 自动换行流式布局的RadioGroup
- Android RadioGroup 换行, 支持多行多列
- radio控件item设置自动换行的方法
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- 可以换行的RadioGroup
- android之自定义ViewGroup和自动换行的布局的实现(支持按钮间隔)
- [自定义控件系列2]--进阶篇:可自动换行的ViewGroup