IOSRadioGroup

来源:互联网 发布:拉货搬家软件 编辑:程序博客网 时间:2024/06/05 17:08


TextView Button RadioButton

public class Button extends TextView {    public Button(Context context) {        this(context, null);    }    public Button(Context context, AttributeSet attrs) {        this(context, attrs, com.android.internal.R.attr.buttonStyle);    }    public Button(Context context, AttributeSet attrs, int defStyleAttr) {        this(context, attrs, defStyleAttr, 0);    }    public Button(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);    }    @Override    public CharSequence getAccessibilityClassName() {        return Button.class.getName();    }}
TextView 和 Button 区别,一个用了 textViewStyle,一个用了 buttonStyle。


CompoundButton 是 RadioButton 的父类 ,它和 Button 的区别:

View 的 onTouchEvent 会调用 performClick。

    @Override    public boolean performClick() {        toggle();        // ...    }
  public void toggle() {        setChecked(!mChecked);    }
    public void setChecked(boolean checked) {        if (mChecked != checked) {            mChecked = checked;            refreshDrawableState();            notifyViewAccessibilityStateChangedIfNeeded(                    AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);            // Avoid infinite recursions if setChecked() is called from a listener            if (mBroadcasting) {                return;            }            mBroadcasting = true;            if (mOnCheckedChangeListener != null) {                mOnCheckedChangeListener.onCheckedChanged(this, mChecked);            }            if (mOnCheckedChangeWidgetListener != null) {                mOnCheckedChangeWidgetListener.onCheckedChanged(this, mChecked);            }            mBroadcasting = false;                    }    }
RadioButton 重写了 toggle ,只允许选中:

   @Override    public void toggle() {        // we override to prevent toggle when the radio is already        // checked (as opposed to check boxes widgets)        if (!isChecked()) {            super.toggle();        }    }
为什么 RadioButton 是可选中的,Button 确不行:

   @Override    protected int[] onCreateDrawableState(int extraSpace) {        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);        if (isChecked()) {            mergeDrawableStates(drawableState, CHECKED_STATE_SET);        }        return drawableState;    }


而 RadioGroup 就是可以监听选中并清除其他子 RadioButton 选中的 LinearLayout。


-----------------------------------------------------------------------------------------  进入正题


https://github.com/Kaopiz/android-segmented-control


很棒的库,虽说不要重复造轮子,但我认为摸索是必要的。

利用之前的知识,外加 RadioButton 隐藏 ButtonDrawable 后,很容易做到。



除了 setCornerRaduis ,还有更细致的 setCornRadii 可用,然后:



有点像样了,还有个问题,相邻的 stroke 应该只显示一条。

我是没想到怎么解决,看看作者的做法:

    layoutParams.setMargins(-strokeWidth, 0, 0, 0);


真是太聪明了。

RadioGroup 在 onMeasure 和 onLayout 方面其实就是 LinearLayout。

LinearLayout 的 onMeasure ,依赖于 child view 的 onMeasure 结果。

缩小 child view 是无济于事的,drawable 重画时会随 View 扩展。


这里的做法,是把 “选项二” 和 “选项三” 向左平移了 strokeWidth。

onMeasure 时总长度,确实减少了 leftMargin。

      mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin +                           lp.rightMargin + getNextLocationOffset(child));

onLayout 时向确实向左偏了 leftMargin,但 child 大小是不变的。

   childLeft += lp.leftMargin;                setChildFrame(child, childLeft + getLocationOffset(child), childTop,                        childWidth, childHeight);


最终结果图:



开源库中还是使用了矢量字体,TransitionDrawable 渐变切换,还加了按下的 maskDrawable 的效果等等。

  int maskColor = Color.argb(50, Color.red(mTintColor), Color.green(mTintColor), Color.blue(mTintColor));        maskDrawable.setColor(maskColor);    


代码:

public class IOSRadioGroup extends RadioGroup {    private int cornerRadius;    private int mainColor;    final int strokeWidth = 2;    float[] leftCornerRadii;    float[] middleCornerRadii;    float[] rightCornerRadii;    //    public IOSRadioGroup(Context context) {        super(context);    }    public IOSRadioGroup(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundCornerTextView);        float dp = typedArray.getDimension(R.styleable.RoundCornerTextView_rc_corner_radius, 0.0f);        cornerRadius = dp2px(context, dp);        leftCornerRadii = new float[]{cornerRadius, cornerRadius, 0, 0, 0, 0, cornerRadius, cornerRadius};        middleCornerRadii = new float[]{0, 0, 0, 0, 0, 0, 0, 0};        rightCornerRadii = new float[]{0, 0, cornerRadius, cornerRadius, cornerRadius, cornerRadius, 0, 0};        mainColor = typedArray.getColor(R.styleable.RoundCornerTextView_rc_background_color, Color.TRANSPARENT);        typedArray.recycle();    }    //    @Override    protected void onFinishInflate() {        super.onFinishInflate();        init();    }    //    @Override    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {        View first = getChildAt(0);        if (child != first) {            LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();            // Third Point            // child 的大小没有变化,但位置会发生了变化,有了些许重叠。            layoutParams.setMargins(-strokeWidth, 0, 0, 0);        }        super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);    }    //        private void init() {        for (int i = 0; i != getChildCount(); i++) {            RadioButton child = (RadioButton) getChildAt(i);            // Second Point            // 不同 child 的 stroke 形状不同            float[] radii;            if (i == 0) {                radii = leftCornerRadii;            } else if (i == getChildCount() - 1) {                radii = rightCornerRadii;            } else {                radii = middleCornerRadii;            }            changeChildBackground(child, radii);        }    }    //    private void changeChildBackground(RadioButton radioButton, float[] cornerRadii) {        GradientDrawable unchecked = new GradientDrawable();        unchecked.setCornerRadii(cornerRadii);        unchecked.setColor(Color.WHITE);        unchecked.setStroke(strokeWidth, mainColor);        GradientDrawable checked = new GradientDrawable();        checked.setCornerRadii(cornerRadii);        checked.setColor(mainColor);        StateListDrawable background = new StateListDrawable();        background.addState(new int[]{-android.R.attr.state_checked}, unchecked);        background.addState(new int[]{android.R.attr.state_checked}, checked);        radioButton.setBackground(background);        // First Point        // 把默认的 style 中的 ButtonDrawable 去除。        radioButton.setButtonDrawable(null);        ColorStateList colorStateList = new ColorStateList(                new int[][]{{-android.R.attr.state_checked}, {android.R.attr.state_checked}},                new int[]{mainColor, Color.WHITE}        );        radioButton.setTextColor(colorStateList);    }    //    protected int dp2px(Context context, float dp) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dp * scale + 0.5f);    }    }




0 0