使用 RadioGroup 和 ViewPager 实现更加可定制的效果。
背景
昨天设计图刚出一点,写了《Android 必知必会 - 动态切换着色模式和全屏模式》,记录了动态修改页面显示模式的方式。今天又有新图,不过设计师只考虑 iOS 平台的设计,拿到设计图发现 TabLayout + ViewPager
的套路实现起来很麻烦,考虑了下,为了方便,决定使用 RadioGroup + ViewPager
来实现,之所以使用 RadioGroup
,是因为它内部多个 RadioButton
的状态是互斥的,也就是只有一个是选中状态,不需要我们进行多余的处理。总体来说比较简单,就是细节略多了点。
主要知识点:
- 自定义
RadioButton
样式 : selector + shape
- 自定义
RadioButton
文字样式 : selector
ViewPager + Fragment
及其适配器
RadioGroup
状态监听
ViewPager
页面切换监听
实现
先看效果图:
思路
UI:
- 顶部是
RadioGroup
,内部包含两个 RadioButton
- 中间是
ViewPager
联动事件:
ViewPager
- 需要为
ViewPager
写适配器,以配合 Fragment
- 使用
addOnPageChangeListener()
为其添加监听页面变动的事件
- 在
onPageSelected(int position)
方法中修改 RadioGroup
中 RadioButton
的选中状态
RadioGroup
- 设置
setOnCheckedChangeListener
监听,并在其中修改 ViewPager
的状态
实现 UI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| <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" >
<RelativeLayout android:layout_width="match_parent" android:layout_height="45dp" android:background="@color/title_bar">
<RadioGroup android:id="@+id/main_top_rg" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_centerInParent="true" android:gravity="center" android:orientation="horizontal">
<RadioButton android:id="@+id/top_rg_a" android:layout_width="76dp" android:layout_height="29dp" android:background="@drawable/top_r_bg" android:button="@null" android:checked="true" android:gravity="center" android:text="@string/main_tab1" android:textColor="@drawable/top_r_text" android:textColorHighlight="@color/title_bar" android:textSize="15sp"/>
<RadioButton android:id="@+id/top_rg_b" android:layout_width="76dp" android:layout_height="29dp" android:background="@drawable/top_r_bg2" android:button="@null" android:gravity="center" android:layout_marginLeft="-1dp" android:text="@string/main_tab2" android:textColor="@drawable/top_r_text" android:textColorHighlight="@color/title_bar" android:textSize="15sp"/> </RadioGroup>
<ImageView android:id="@+id/main_top_right" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:paddingLeft="@dimen/left_padding" android:paddingRight="@dimen/right_padding" android:src="@drawable/main_search" /> </RelativeLayout>
<android.support.v4.view.ViewPager android:id="@+id/main_viewpager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" />
</LinearLayout>
|
重点在 RadioButton
的几个属性:
android:button="@null"
隐藏 RadioButton
默认的图标
android:background="@drawable/top_r_bg"
设置背景,实际上是一个 selector
android:textColor="@drawable/top_r_text"
设置文字颜色,它也是一个 selector
- 对于第二个
RadioButton
: android:layout_marginLeft="-1dp"
和描边宽度一样,防止出现间隙
下面把 xml 代码放在一起看,它们都放在 drawable
目录下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/top_r_bg_a" android:state_checked="false"/> <item android:drawable="@drawable/top_r_bg_b" android:state_checked="true"/> </selector>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:bottomLeftRadius="2dp" android:bottomRightRadius="0dp" android:topLeftRadius="2dp" android:topRightRadius="0dp" /> <stroke android:width="1dp" android:color="@color/white"/> <solid android:color="@color/transparent"/> </shape>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:bottomLeftRadius="2dp" android:topLeftRadius="2dp"/> <solid android:color="@color/white"/> </shape>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@color/white" android:state_checked="false"/> <item android:color="@color/title_bar" android:state_checked="true"/> </selector>
|
上面只贴出了左边按钮的样式,右边的类似,不再张贴。UI 到这里已经完成,下面看事件:
实现联动事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| private void init() { List<Fragment> fragments = new ArrayList<>(); fragments.add(new FragmentMain01A()); fragments.add(new FragmentMain01B());
NotePagerAdapter pagerAdapter = new NotePagerAdapter(getFragmentManager(), fragments); mainViewpager.setAdapter(pagerAdapter);
mainViewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override public void onPageSelected(int position) { if (position == 0) radioButtonA.setChecked(true); else radioButtonB.setChecked(true); }
@Override public void onPageScrollStateChanged(int state) {
} });
mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { if (checkedId == radioButtonA.getId()) mainViewpager.setCurrentItem(0); else if (checkedId == radioButtonB.getId()) mainViewpager.setCurrentItem(1); } });
mainViewpager.setCurrentItem(0); }
|
对了,还有 NotePagerAdapter
的代码,这个比较简单,是 ViewPager
和 Fragment
的适配器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class NotePagerAdapter extends FragmentStatePagerAdapter { private List<Fragment> mFragments;
public NotePagerAdapter(FragmentManager fm, List<Fragment> fragments) { super(fm); mFragments = fragments; }
@Override public int getCount() { return mFragments.size(); }
@Override public Fragment getItem(int position) { return mFragments.get(position); }
}
|
总结
注意,以上代码使用的是 android.support.v4
包的类,理论上不使用 V4
包是没问题的。
看完整体的代码发现并没什么难点,纯属基础知识的叠加,主要是 UI 控件上的细节需要处理的比较多。
再者,如果顶部的控件超过2个,还需要更多的 xml 文件,顶部的几个控件是可以封装成一个自定义 View 的,甚至加上中间的 ViewPager
一起封装。等待我后面的成果吧。如果有什么疑问或建议,可以通过文末的联系方式和我交流。
最后,纪念一下自己今天正式成为 CSDN博客专家
,祝愿广大程序员都能在编程的路上有所成就!
PS:你可以通过下面的方式和我联系