IOSRadioGroup


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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值