您的位置:首页 > 移动开发 > Android开发

可自动换行的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)

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android