可自动换行的RadioGroup

来源:互联网 发布:网易养猪场知乎 编辑:程序博客网 时间:2024/06/08 00:40
主要重写了onMeasure和onLayout
import android.content.Contextimport android.content.res.TypedArrayimport android.support.annotation.IdResimport android.util.AttributeSetimport android.view.Viewimport android.view.ViewGroupimport android.widget.CompoundButtonimport android.widget.LinearLayoutimport android.widget.RadioButtonimport java.util.concurrent.atomic.AtomicIntegeropen 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 MultiRadioGroup.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)    }}

原创粉丝点击