Android UI之自定义头部指示器实现音乐地区选择

1. 简介 

本文将记录的是一些有效的自定义指示器demo,诚然Indicator的开源框架还是比较多的,我们在具体具体中可以衡量。一些简单的自定义基础还是有必要好好掌握的。

2. demo样例

2.1 图片背景选择+ViewPager样式

首先看下效果吧:

如下图所示,可以滑动viewPager来滑动头部的指示器;也可以通过点击指示器来选择不同的界面

具体实现:

首先就是布局咯:和 tabLayout+ViewPager的形式是一样的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    tools:context=".indicator.IndicatorOneActivity">
        <LinearLayout
            android:layout_gravity="center_horizontal"
            android:layout_width="wrap_content"
            android:layout_height="50dp"
            android:background="#ffce3d3a">

            <ImageView
                android:id="@+id/iv_title_gank"
                android:layout_width="55dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:background="?attr/selectableItemBackgroundBorderless"
                android:src="@drawable/titlebar_disco" />

            <ImageView
                android:id="@+id/iv_title_one"
                android:layout_width="55dp"
                android:layout_height="match_parent"
                android:background="?attr/selectableItemBackgroundBorderless"
                android:src="@drawable/titlebar_music" />

            <ImageView
                android:id="@+id/iv_title_dou"
                android:layout_width="55dp"
                android:layout_height="match_parent"
                android:background="?attr/selectableItemBackgroundBorderless"
                android:src="@drawable/titlebar_friends" />

        </LinearLayout>
        <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:descendantFocusability="blocksDescendants"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </android.support.v4.view.ViewPager>
    <!-- android:descendantFocusability="blocksDescendants"
         解决滑动冲突的
    -->
</LinearLayout>

单个imageView的指示器背景布局如下:stateListDrawable

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/titlebar_music_selected" android:state_selected="true"/>
    <item android:drawable="@drawable/titlebar_music_normal" android:state_selected="false"/>
    <item android:drawable="@drawable/titlebar_music_normal" android:state_pressed="false"/>
</selector>

activity中的核心代码如下:

    // 设置点击事件 --- 改变之前判断是否被选中了---
    private void setListener() {
        ivGank.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //不然cpu会有损耗
                if (mViewPager.getCurrentItem() != 0) {
                    ivGank.setSelected(true);
                    ivBook.setSelected(false);
                    ivMe.setSelected(false);
                    mViewPager.setCurrentItem(0);
                }
            }
        });

        ivBook.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //不然cpu会有损耗
                if (mViewPager.getCurrentItem() != 1) {
                    ivGank.setSelected(false);
                    ivBook.setSelected(true);
                    ivMe.setSelected(false);
                    mViewPager.setCurrentItem(1);
                }
            }
        });

        ivMe.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //不然cpu会有损耗
                if (mViewPager.getCurrentItem() != 2) {
                    ivGank.setSelected(false);
                    ivBook.setSelected(false);
                    ivMe.setSelected(true);
                    mViewPager.setCurrentItem(2);
                }
            }
        });
    }

    private void setViewPager() {
        ArrayList<Fragment> fragments = new ArrayList<>();
        fragments.add(new GankFragment());
        fragments.add(new GankFragment());
        fragments.add(new MeFragment());
        mViewPager.setAdapter(new MyFragmentAdapter(getSupportFragmentManager(),fragments));
        mViewPager.setOffscreenPageLimit(2);
        // 设置viewpage滑动监听 ---- 当滑到某个界面时 标题背景改变
        mViewPager.addOnPageChangeListener(this);
        // 设置默认选中第一个 通过选中的背景设置切换
        ivGank.setSelected(true);
        mViewPager.setCurrentItem(0);
    }

还是很easy的,因为我们接触的项目有可能TabLayout不能满足我们的需求,这时候可以去GitHub上找轮子,也可以自己来定义View,也算是一种积累吧。总之 viewPager这一组件讲真还是特别重要的,有必要好好的学习下。

2.2 RadioGroup样例

可以观察下效果:

扫描二维码关注公众号,回复: 3600284 查看本文章
    <RadioGroup
        android:layout_marginTop="20dp"
        android:layout_gravity="center_horizontal"
        android:id="@+id/radioGroup"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <RadioButton
            android:id="@+id/rb1"
            android:padding="8dp"
            android:button="@null"
            android:text="贡献周榜"
            android:background="@drawable/drawable_selector_left"
            android:textColor="@color/text_radio_color"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <RadioButton
            android:id="@+id/rb2"
            android:padding="8dp"
            android:button="@null"
            android:text="贡献总榜"
            android:background="@drawable/drawable_selector_right"
            android:textColor="@color/text_radio_color"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </RadioGroup>

text_radio_color.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#000000" android:state_checked="false" />
    <item android:color="#00ff00" android:state_checked="true" />
</selector>

drawable_selector_right.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true" android:drawable="@drawable/drawable_right_selected_true"/>
    <item android:state_checked="false" android:drawable="@drawable/drawable_right_selected_false"/>
</selector>

<!--false -->
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >
    <solid
        android:color="#ffffff"/>
    <corners
        android:topRightRadius="5dp"
        android:bottomRightRadius="5dp"/>

</shape>

<!--true-->
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >
    <solid
        android:color="#ff0000"/>
    <corners
        android:topRightRadius="5dp"
        android:bottomRightRadius="5dp"/>

</shape>

2.3 究极RadiaButton实现仿58同城热门城市选择

首先看下效果吧:

如上所示,基本和58上的一样。下面将解析具体的绘制。

布局文件如下:

    <com.example.mydairytestproject.views.WubaTownRadioGroup
        android:layout_gravity="center_horizontal"
        android:gravity="center"
        android:orientation="horizontal"
        android:id="@+id/city_hot_tab"
        android:layout_marginTop="100dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <RadioButton android:textSize="14sp"
            android:id="@+id/city"
            android:textColor="@color/city_hot_tab_text_color"
            android:gravity="center"
            android:background="@drawable/city_left_bg"
            android:layout_width="80dp"
            android:layout_height="29dp"
            android:button="@null"
            android:text="城市" />

        <RadioButton android:textSize="14sp"
            android:id="@+id/town"
            android:textColor="@color/city_hot_tab_text_color"
            android:gravity="center"
            android:background="@drawable/city_center_bg"
            android:layout_width="80dp"
            android:layout_height="29dp"
            android:button="@null"
            android:text="乡镇" />

        <RadioButton android:textSize="14sp"
            android:id="@+id/country"
            android:textColor="@color/city_hot_tab_text_color"
            android:gravity="center"
            android:background="@drawable/city_right_bg"
            android:layout_width="80dp"
            android:layout_height="29dp"
            android:button="@null"
            android:text="海外" />
    </com.example.mydairytestproject.views.WubaTownRadioGroup>

和前面的案例是相类似的,无非就是 radioGroup+radioButton+stateListDrawable+colorSelector等完成的效果。这里drawable包括color文件我就不给出来了,和前面的案例相类似。值得注意的是,可以发现58案例比简易案例多了边缘框和中间的分割线,这就是不同点,也是需要指出的具体细节,接下来就相应的进行解析。

 编写自定义控件继承自RadioGroup,绘制背景边框,接着再绘制分割线即可。代码如下所示。

public class WubaTownRadioGroup extends RadioGroup
{
    // 边缘 分割线颜色
    private int bgColor = Color.parseColor("#ff552e");
    // 画笔
    private Paint mpaint;
    // 圆弧半径 === 注意这里的半径 应当和xml里设置的左右的corners 呈对应关系
    private int roundWidth;
    // 边缘线宽度
    private int strokeWidth;

    public WubaTownRadioGroup(Context paramContext)
    {
        super(paramContext);
    }

    public WubaTownRadioGroup(Context paramContext, AttributeSet paramAttributeSet)
    {
        super(paramContext, paramAttributeSet);
    }

    private void drawDivider(Canvas paramCanvas)
    {
        if (getOrientation() == LinearLayout.HORIZONTAL)
        {
            int j = getChildCount();
            if (j > 1)
            {
                int i = 1;
                while (i < j)
                {
                    int k = getChildAt(i).getLeft();
                    paramCanvas.drawLine(k, 0.0F, k, getMeasuredHeight(), this.mpaint);
                    i += 1;
                }
            }
        }
    }

    private void drawRoundBackGround(Canvas paramCanvas)
    {
        this.roundWidth = ((int)TypedValue.applyDimension(1, 4.0F, getResources().getDisplayMetrics()));
        float f = this.mpaint.getStrokeWidth() - 1.0F;
        // 绘制圆角矩形
        paramCanvas.drawRoundRect(new RectF(
                0.0F + f,
                0.0F + f,
                getMeasuredWidth() - f,
                getMeasuredHeight() - f),
                this.roundWidth,
                this.roundWidth,
                this.mpaint);
    }
    

    private void initPaint()
    {
        // 这里要做适配
        this.strokeWidth = ((int) TypedValue.applyDimension(1, 1.0F, getResources().getDisplayMetrics()));
        this.mpaint = new Paint();
        this.mpaint.setStrokeWidth(this.strokeWidth);
        // 设置抗锯齿 优化显示效果
        this.mpaint.setAntiAlias(true);
        // 设置防止抖动
        this.mpaint.setDither(true);
        this.mpaint.setStyle(Paint.Style.STROKE);
        this.mpaint.setColor(this.bgColor);
    }

    @Override
    protected void dispatchDraw(Canvas paramCanvas)
    {
        super.dispatchDraw(paramCanvas);
        if ((getMeasuredHeight() > 0) && (getMeasuredWidth() > 0))
        {
            initPaint();
            drawRoundBackGround(paramCanvas);
            drawDivider(paramCanvas);
        }
    }

    public void setBgColor(int paramInt)
    {
        this.bgColor = paramInt;
    }
}

猜你喜欢

转载自blog.csdn.net/crazyZhangxl/article/details/83038917