SegmentedGroup自定义控件的使用

先上效果图,不耽误大伙时间:



因为公司业务需要,需要做一个类似的标题效果。数据是从服务器动态获取的,所以标题的数目是不固定的。该自定义控件可以实现标题的动态添加、

设置边线的颜色、设置选中的文字颜色、设置选中的背景颜色、设置点击监听等一些列方法。

布局文件,非常简单:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="cn.oneday.segmentedgroupdemo.MainActivity">

    <cn.oneday.segmentedgroupdemo.SegmentedGroup
        android:id="@+id/segment_group_sg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_gravity="center"
        android:orientation="horizontal"
        app:sc_border_width="@dimen/dp_2" // 边线的宽度
        app:sc_checked_text_color="@color/green_light" // 被选中的文本的颜色
        app:sc_corner_radius="@dimen/dp_8" //圆角的角度
        app:sc_tint_color="@color/brown" /> // 未被选中的文本颜色
</RelativeLayout>

自定义SegmentedGroup属性:

<!--SegmentedGroup自定义属性-->
    <declare-styleable name="SegmentedGroup">
        <attr name="sc_corner_radius" format="dimension" /><!--SegmentedGroup角度-->
        <attr name="sc_border_width" format="dimension" /><!--SegmentedGroup边线宽度-->
        <attr name="sc_tint_color" format="color" />
        <attr name="sc_checked_text_color" format="color" />
    </declare-styleable>

SegmentedGroup代码:

package cn.oneday.segmentedgroupdemo;

import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RadioGroup;

public class SegmentedGroup extends RadioGroup {

    private int mMarginDp;
    private Resources resources;

    private LayoutSelector mLayoutSelector;
    /**
     * SegmentedGroup圆角角度
     */
    private Float mCornerRadius;

    /**
     * 被选中的RadioButton文本的颜色,默认白色
     */
    private int mCheckedTextColor = Color.WHITE;
    /**
     * SegmentedGroup边线的默认宽度
     */
    private final int radio_button_stroke_border = R.dimen.dp_2;
    /**
     * SegmentedGroup默认的圆角角度
     */
    private final int radio_button_corner_radius = R.dimen.dp_4;
    /**
     * 被选中RadioButton的默认背景色
     */
    private final int radio_button_selected_color = R.color.white;
    /**
     * 未被选中的文本的颜色
     */
    private int mTintColor;
    /**
     * SegmentedGroup边线颜色
     */
    private int mStrokeColor;
    /**
     * RadioButton被选中的背景色
     */
    private int mCheckColor;

    public SegmentedGroup(Context context) {
        super(context);
        init();
        mLayoutSelector = new LayoutSelector(mCornerRadius);
    }

    /* Reads the attributes from the layout */
    public SegmentedGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
        initAttrs(attrs);
        mLayoutSelector = new LayoutSelector(mCornerRadius);
    }

    private void init() {
        resources = getResources();
        mTintColor = resources.getColor(radio_button_selected_color);
        mStrokeColor = mTintColor;
        mCheckColor = mTintColor;
        mMarginDp = (int) getResources().getDimension(radio_button_stroke_border);
        mCornerRadius = getResources().getDimension(radio_button_corner_radius);
    }

    public void setmMarginDp(int dp) {
        mMarginDp = dp;
    }

    private void initAttrs(AttributeSet attrs) {
        TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.SegmentedGroup, 0, 0);
        try {
            mMarginDp = (int) typedArray.getDimension(
                    R.styleable.SegmentedGroup_sc_border_width,
                    getResources().getDimension(radio_button_stroke_border));

            mCornerRadius = typedArray.getDimension(
                    R.styleable.SegmentedGroup_sc_corner_radius,
                    getResources().getDimension(radio_button_corner_radius));

            mTintColor = typedArray.getColor(
                    R.styleable.SegmentedGroup_sc_tint_color,
                    getResources().getColor(radio_button_selected_color));
            mCheckedTextColor = typedArray.getColor(
                    R.styleable.SegmentedGroup_sc_checked_text_color,
                    getResources().getColor(android.R.color.white));

        } finally {
            typedArray.recycle();
        }
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        //Use holo light for default
        updateBackground();
    }

    public void setStrokeColor(int mStrokeColor) {
        this.mStrokeColor = mStrokeColor;
    }

    public void setTintColor(int tintColor) {
        mTintColor = tintColor;
        updateBackground();
    }

    public void setTintColor(int tintColor, int checkedTextColor) {
        mTintColor = tintColor;
        mCheckedTextColor = checkedTextColor;
        updateBackground();
    }

    public void setCheckedTextColor(int mCheckedTextColor) {
        this.mCheckedTextColor = mCheckedTextColor;
    }

    public void setCheckColor(int mCheckColor) {
        this.mCheckColor = mCheckColor;
    }

    public void updateBackground() {
        int count = super.getChildCount();
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            updateBackground(child);
            // If this is the last view, don't set LayoutParams
            if (i == count - 1) break;

            LayoutParams initParams = (LayoutParams) child.getLayoutParams();
            LayoutParams params = new LayoutParams(initParams.width, initParams.height, initParams.weight);
            // Check orientation for proper margins
            if (getOrientation() == LinearLayout.HORIZONTAL) {
                params.setMargins(0, 0, -mMarginDp, 0);
            } else {
                params.setMargins(0, 0, 0, -mMarginDp);
            }
            child.setLayoutParams(params);
        }
    }

    private void updateBackground(View view) {
        int checked = mLayoutSelector.getSelected();
        int unchecked = mLayoutSelector.getUnselected();
        //Set text color
        ColorStateList colorStateList = new ColorStateList(new int[][]{
                {android.R.attr.state_pressed},
                {-android.R.attr.state_pressed, -android.R.attr.state_checked},
                {-android.R.attr.state_pressed, android.R.attr.state_checked}},
                new int[]{Color.GRAY, mTintColor, mCheckedTextColor});
        ((Button) view).setTextColor(colorStateList);

        //Redraw with tint color
        Drawable checkedDrawable = resources.getDrawable(checked).mutate();
        Drawable uncheckedDrawable = resources.getDrawable(unchecked).mutate();
        ((GradientDrawable) checkedDrawable).setColor(mCheckColor);

        ((GradientDrawable) checkedDrawable).setStroke(mMarginDp, mStrokeColor);
        ((GradientDrawable) uncheckedDrawable).setStroke(mMarginDp, mStrokeColor);

        //Set proper radius
        ((GradientDrawable) checkedDrawable).setCornerRadii(mLayoutSelector.getChildRadii(view));
        ((GradientDrawable) uncheckedDrawable).setCornerRadii(mLayoutSelector.getChildRadii(view));

        //Create drawable
        StateListDrawable stateListDrawable = new StateListDrawable();
        stateListDrawable.addState(new int[]{-android.R.attr.state_checked}, uncheckedDrawable);
        stateListDrawable.addState(new int[]{android.R.attr.state_checked}, checkedDrawable);

        //Set button background
        if (Build.VERSION.SDK_INT >= 16) {
            view.setBackground(stateListDrawable);
        } else {
            view.setBackgroundDrawable(stateListDrawable);
        }
    }

    /*
     * This class is used to provide the proper layout based on the view.
     * Also provides the proper radius for corners.
     * The layout is the same for each selected left/top middle or right/bottom button.
     * float tables for setting the radius via Gradient.setCornerRadii are used instead
     * of multiple xml drawables.
     */
    private class LayoutSelector {

        private int children;
        private int child;
        private final int SELECTED_LAYOUT = R.drawable.radio_checked;
        private final int UNSELECTED_LAYOUT = R.drawable.radio_unchecked;

        private float r;    //this is the radios read by attributes or xml dimens
        private final float r1 = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP
                , 0.1f, getResources().getDisplayMetrics());    //0.1 dp to px
        private final float[] rLeft;    // left radio button
        private final float[] rRight;   // right radio button
        private final float[] rMiddle;  // middle radio button
        private final float[] rDefault; // default radio button
        private final float[] rTop;     // top radio button
        private final float[] rBot;     // bot radio button
        private float[] radii;          // result radii float table

        public LayoutSelector(float cornerRadius) {
            children = -1; // Init this to force setChildRadii() to enter for the first time.
            child = -1; // Init this to force setChildRadii() to enter for the first time
            r = cornerRadius;
            rLeft = new float[]{r, r, r1, r1, r1, r1, r, r};
            rRight = new float[]{r1, r1, r, r, r, r, r1, r1};
            rMiddle = new float[]{r1, r1, r1, r1, r1, r1, r1, r1};
            rDefault = new float[]{r, r, r, r, r, r, r, r};
            rTop = new float[]{r, r, r, r, r1, r1, r1, r1};
            rBot = new float[]{r1, r1, r1, r1, r, r, r, r};
        }

        private int getChildren() {
            return SegmentedGroup.this.getChildCount();
        }

        private int getChildIndex(View view) {
            return SegmentedGroup.this.indexOfChild(view);
        }

        private void setChildRadii(int newChildren, int newChild) {

            // If same values are passed, just return. No need to update anything
            if (children == newChildren && child == newChild)
                return;

            // Set the new values
            children = newChildren;
            child = newChild;

            // if there is only one child provide the default radio button
            if (children == 1) {
                radii = rDefault;
            } else if (child == 0) { //left or top
                radii = (getOrientation() == LinearLayout.HORIZONTAL) ? rLeft : rTop;
            } else if (child == children - 1) {  //right or bottom
                radii = (getOrientation() == LinearLayout.HORIZONTAL) ? rRight : rBot;
            } else {  //middle
                radii = rMiddle;
            }
        }

        /* Returns the selected layout id based on view */
        public int getSelected() {
            return SELECTED_LAYOUT;
        }

        /* Returns the unselected layout id based on view */
        public int getUnselected() {
            return UNSELECTED_LAYOUT;
        }

        /* Returns the radii float table based on view for Gradient.setRadii()*/
        public float[] getChildRadii(View view) {
            int newChildren = getChildren();
            int newChild = getChildIndex(view);
            setChildRadii(newChildren, newChild);
            return radii;
        }
    }
}

SegmentedGroup帮助类:

package cn.oneday.segmentedgroupdemo;

import android.content.Context;
import android.view.View;
import android.widget.RadioButton;

public class SegmentGroupHelper {
    public static RadioButton createRadioButton(Context context, int id, String name) {
        RadioButton radioButton = (RadioButton) View.inflate(context, R.layout.radio_button_item, null);
        return initRadioButton(radioButton, id, name);
    }

    public static RadioButton createRadioButtonNoBorder(Context context, int id, String name) {
        RadioButton radioButton = (RadioButton) View.inflate(context, R.layout.tab_radio_item, null);
        return initRadioButton(radioButton, id, name);
    }

    private static RadioButton initRadioButton(RadioButton radioButton, int id, String name) {
        radioButton.setId(id);
        radioButton.setText(name);
        return radioButton;
    }
}

两个布局文件,也比较简单:

radio_button_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/RadioButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

tab_radio_item.xml:

<?xml version="1.0" encoding="utf-8"?>

<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/RadioButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:minHeight="@dimen/dp_40"
    android:minWidth="@dimen/dp_80" />

自定义style样式:

<style name="RadioButton">
        <item name="android:textColor">@color/white</item>
        <item name="android:paddingTop">@dimen/dp_8</item>
        <item name="android:paddingBottom">@dimen/dp_8</item>
        <item name="android:paddingLeft">@dimen/dp_18</item>
        <item name="android:paddingRight">@dimen/dp_18</item>
        <item name="android:minHeight">@dimen/dp_20</item>
        <item name="android:minWidth">@dimen/dp_60</item>
        <item name="android:textSize">@dimen/sp_16</item>
        <item name="android:gravity">center</item>
        <item name="android:button">@null</item>
    </style>

使用方法:

package cn.oneday.segmentedgroupdemo;

import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private SegmentedGroup mSegmentGroup;
    private ArrayList<String> mNames = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
    }

    private void initView() {
        mSegmentGroup = (SegmentedGroup) findViewById(R.id.segment_group_sg);
    }

    private void initData() {
        // 添加模拟数据
        mNames.add("路飞");
        mNames.add("佐罗");
        mNames.add("乌索普");
        mNames.add("弗兰奇");
        // 添加子view
        for (int x = 0; x < mNames.size(); x++) {
            RadioButton radioButton = SegmentGroupHelper.createRadioButton(this, x, mNames.get(x));
            mSegmentGroup.addView(radioButton);
            //  mSegmentGroup.updateBackground();
        }

        mSegmentGroup.setCheckColor(Color.BLACK); // 设置被选中背景色
        mSegmentGroup.setStrokeColor(Color.BLACK); // 设置边线颜色
        mSegmentGroup.updateBackground(); // 更新背景颜色的核心方法,不要忘记调用

        // 设置点击监听
        mSegmentGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                Toast.makeText(MainActivity.this, "name = [" + mNames.get(checkedId) + "], checkedId = [" + checkedId + "]", Toast.LENGTH_SHORT).show();
            }
        });
    }
}


以此标记,方便以后查阅。

源码在此:源码点我







  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可自定义样式、功能全面的分段件。项目地址:https://github.com/klongmitre/android-segmented-control-view效果图:如何使用xml中直接创建<org.mitre.ascv.AndroidSegmentedControlView         android:id="@ id/androidSegmentedControlView"         android:layout_width="match_parent"         android:layout_height="wrap_content"         ascv:ascv_defaultSelection="0"         ascv:ascv_unselectedTextColor="@color/test_attr_unselected_text_color"         ascv:ascv_selectedTextColor="@color/test_attr_selected_text_color"         ascv:ascv_selectedColor="@color/test_attr_selected_color"         ascv:ascv_unselectedColor="@color/test_attr_unselected_color"         ascv:ascv_items="@array/three_state_option"/>2. java中添加监听器,监听item的切换ascv = (AndroidSegmentedControlView)this.findViewById(R.id.androidSegmentedControlView); ascv.setIdentifier("ascv01"); //ascv.setItems(new String[]{"Test1aaaaa", "Test2", "Test3"}, new String[]{"1", "2", "3"}); ascv.setOnSelectionChangedListener(new OnSelectionChangedListener(){     @Override     public void newSelection(String identifier, String value) {//当item切换时触发  Toast.makeText(MainActivity.this, "identifier:" identifier "  value:" value, Toast.LENGTH_SHORT).show();     } });参数identifier是当有多个分段件时,同时使用一个监听器时,用于区别是哪个触发了事件。属性说明属性名类型使用说明ascv_unselectedTextColorreference未选中的item的文字颜色ascv_unselectedColorreference未选中的item的背景颜色,不包括边框ascv_selectedColorreference选中的item背景的颜色以及边框的颜色ascv_selectedTextColorreference选中的item的文字颜色ascv_itemsreference件item上显示的文字ascv_valuesreference件item的值,会被传给监听器。未设置时,默认使用ascv_items。ascv_equalWidthboolean当item上的文字,即ascv_items设置的文字,长度不一致时,item的宽度是否还等长。ascv_stretchboolean是否被拉伸。即件是否填充整个父容器。ascv_defaultSelectioninteger默认哪个item被选中,下标从0开始ascv_identifierstring件的ID

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值