import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup; import java.lang.reflect.Field;
import java.util.List; /**
* 使用 ViewPager 和 RadioGroup 封装的一个导航控件<p/>
* 有2种布局方式:<br/>
* 1. ViewPager + 图标在上文本在下的tab 栏<br/>
* 2. 仅有文本的tab + ViewPager<br/>
* 只需要调用 viewPagerIndicator.bind(fragments, indicatorEntityList) 方法<br/>
* 其中如果indicatorEntityList 中如果传入图标,就是布局方式1,否则就是布局方式2<br/>
* <br/> Fragment需要用v4的 ,Activity需要继承自 FragmentActivity
*/
public class ViewPagerIndicator extends LinearLayout implements RadioGroup.OnCheckedChangeListener { /**
* 需要的实体类<p/>
* 如果只设置tab的名字, 则不会显示图标<br/>
* 如果设置了图标,会显示对应的图标
*/
public static class IndicatorEntity {
/** tab的名字 */
String indicator;
/** tab的选中状态和非选中状态的图标 */
int selectedRes, unSelectedRes;
boolean isShowIconEnable; /**
* @param indicator tab的名字
*/
public IndicatorEntity(String indicator) {
this.indicator = indicator;
isShowIconEnable = false;
} /**
* @param indicator tab的名字
* @param selectedRes tab的选中状态的图标
* @param unSelectedRes tab的非选中状态的图标
*/
public IndicatorEntity(String indicator, int selectedRes, int unSelectedRes) {
this.indicator = indicator;
this.selectedRes = selectedRes;
this.unSelectedRes = unSelectedRes;
isShowIconEnable = true;
}
} /** 选中和非选中tab的前景色, 也就是字体颜色 */
public static final int selected_fg_Color = 0xff0000ff, unselected_fg_Color = 0xFF000000;
/** 选中和非选中tab的背景色 */
public static final int selected_bg_Color = 0xff00ff00, unselected_bg_Color = 0xcccccccc;
/** 分隔线的颜色 */
public static final int divide_line_color = 0xFF000000;
/** 指示条的颜色 */
public static final int indicator_color = 0xFF0000FF; // 是否允许ViewPager 滑动
private boolean scrollable = true;
// radioGroup 即tab 栏的高度,可以使用 DimenUtil 传入dp单位的高度
private int radioGroupShowIconHeight = 54 * 3;
private int radioGroupGoneIconHeight = 36 * 3;
private int radioGroupHeight = radioGroupShowIconHeight;
private Context context;
// 屏幕宽度
private int mScreenWidth;
private RadioGroup mRadioGroup;
private MyViewPager mViewPager;
private List<IndicatorEntity> indicatorEntityList;
// 是否显示图标
private boolean isShowIconEnable = true; /** 上一次的指示条的位置 */
private int lastSelectedIndex;
/** 指示条控件 */
private View indicatorView; public ViewPagerIndicator(Context context) {
this(context, null);
} public ViewPagerIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public ViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
this.setOrientation(VERTICAL);
// 获取屏幕宽度
DisplayMetrics outMetrics = new DisplayMetrics();
((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
} /** 设置是否允许ViewPager 滑动 */
public void setScrollable(boolean scrollable) {
this.scrollable = scrollable;
} /**
* 绑定页面<br/>
* fragments 和 indicatorEntityList 的数量必须一致
* <p/>
*
* @param fragments 绑定的fragment
* @param indicatorEntityList 绑定的tab的名字或者图标
*/
public void bind(List<Fragment> fragments, List<IndicatorEntity> indicatorEntityList) {
if (fragments == null || fragments.size() <= 0 || indicatorEntityList == null || indicatorEntityList.size() <= 0 || fragments.size() != indicatorEntityList.size())
return;
this.indicatorEntityList = indicatorEntityList;
isShowIconEnable = indicatorEntityList.get(0).isShowIconEnable;
initViews();
mViewPager.setFragments(fragments);
for (int i = 0; i < indicatorEntityList.size(); i++) {
mRadioGroup.addView(generateRadioButton(i));
}
//设置第一个tab为选中状态
((RadioButton) mRadioGroup.getChildAt(0)).setChecked(true);
mViewPager.setCurrentItem(0);
} /** 分隔线 */
private View generateDivideLine() {
View view = new View(context);
view.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
view.setBackgroundColor(divide_line_color);
return view;
} private void initViewPager() {
mViewPager = new MyViewPager(context);
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, 0);
layoutParams.weight = 1;
mViewPager.setLayoutParams(layoutParams);
mViewPager.setId((int) (System.currentTimeMillis() % 10000)); // Id 必须设置,不然会有 NotFoundException 异常
mViewPager.addOnPageChangeListener(mOnPageChangeListener);
} private void initRadioGroup() {
radioGroupHeight = isShowIconEnable ? radioGroupShowIconHeight : radioGroupGoneIconHeight;
mRadioGroup = new RadioGroup(context);
mRadioGroup.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, radioGroupHeight));
mRadioGroup.setOrientation(HORIZONTAL);
mRadioGroup.setOnCheckedChangeListener(this);
} /** 初始化需要添加的添加控件以及事件 */
private void initViews() {
initViewPager();
initRadioGroup();
if (isShowIconEnable) {
this.addView(mViewPager);
this.addView(generateDivideLine());
this.addView(mRadioGroup);
} else {
this.addView(mRadioGroup);
initIndicatorView();
this.addView(indicatorView);
this.addView(generateDivideLine());
this.addView(mViewPager);
}
} private void initIndicatorView() {
indicatorView = new View(context);
LayoutParams layoutParams = new LayoutParams((int) (mScreenWidth / indicatorEntityList.size() * 0.8f), radioGroupHeight / 10);
layoutParams.setMargins((int) (mScreenWidth / indicatorEntityList.size() * 0.1f), -layoutParams.height, 0, 0);
indicatorView.setLayoutParams(layoutParams);
indicatorView.setBackgroundColor(indicator_color);
} private RadioButton generateRadioButton(int index) {
RadioButton rb = new RadioButton(context);
// 均分宽度,TODO 不知道这里用 weight 为什么无法显示出来
rb.setLayoutParams(new LayoutParams(mScreenWidth / indicatorEntityList.size(), ViewGroup.LayoutParams.MATCH_PARENT));
rb.setId(index);
rb.setGravity(Gravity.CENTER);
rb.setText(indicatorEntityList.get(index).indicator);
rb.setPadding(0, radioGroupHeight / 10, 0, radioGroupHeight / 10); // 设置上下边距,不至于挨着边
// rb.setCompoundDrawablePadding(2); // 文本和图片的间距
rb.setButtonDrawable(android.R.color.transparent); // 去掉圆圈圈
return rb;
} /** 处理tab切换以后的ui状态 */
private void setSelectedItem(int position) {
for (int i = 0; i < indicatorEntityList.size(); i++) {
((RadioButton) mRadioGroup.getChildAt(i)).setTextColor(i == position ? selected_fg_Color : unselected_fg_Color); // 字体颜色
if (isShowIconEnable) {
Drawable drawable = ContextCompat.getDrawable(context, i == position ? indicatorEntityList.get(i).selectedRes : indicatorEntityList.get(i).unSelectedRes);
drawable.setBounds(0, 0, radioGroupHeight / 2, radioGroupHeight / 2);
((RadioButton) mRadioGroup.getChildAt(i)).setCompoundDrawables(null, drawable, null, null);// 图标
} else {
mRadioGroup.getChildAt(i).setBackgroundColor(i == position ? selected_bg_Color : unselected_bg_Color); // 背景颜色
}
}
// 设置 indicatorView 动画 TODO indicatorView 动画是在 ViewPager 滑动动画完成后执行的,不是和 ViewPager 同步的
if (indicatorView != null && lastSelectedIndex != position) {
ObjectAnimator.ofFloat(indicatorView, "TranslationX", lastSelectedIndex * mScreenWidth / indicatorEntityList.size(), position * mScreenWidth / indicatorEntityList.size())
.setDuration(300).start();
lastSelectedIndex = position;
}
} @Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (mViewPager != null) mViewPager.setCurrentItem(checkedId);
setSelectedItem(checkedId);
} private ViewPager.OnPageChangeListener mOnPageChangeListener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
} @Override
public void onPageSelected(int position) {
setSelectedItem(position);
} @Override
public void onPageScrollStateChanged(int state) {
}
}; /**
* 自定义ViewPager<p/>
* Override onTouchEvent() 和 onInterceptTouchEvent() 是为了屏蔽滑动事件<br/>
* Override setCurrentItem() 是为了在点击非相邻的tab时,避免中间滚动太多<br/>
*/
class MyViewPager extends ViewPager { private Context context;
private List<Fragment> mFragments;
private MyFragmentPagerAdapter mAdapter; public MyViewPager(Context context) {
this(context, null);
} public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
} /**
* 如果Activity不是继承 FragmentActivity,会crash掉
*
* @param fragments
*/
public void setFragments(List<Fragment> fragments) {
if (!(context instanceof FragmentActivity)) {
throw new ClassCastException("activity need to extents FragmentActivity");
}
mAdapter = new MyFragmentPagerAdapter(((FragmentActivity) context).getSupportFragmentManager());
this.setAdapter(mAdapter);
mFragments = fragments;
mAdapter.notifyDataSetChanged();
} @Override
public boolean onTouchEvent(MotionEvent ev) {
return scrollable && super.onTouchEvent(ev);
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return scrollable && super.onInterceptTouchEvent(ev);
} @Override
public void setCurrentItem(int item) {
try {
Field mFirstLayout = ViewPager.class.getDeclaredField("mFirstLayout");
mFirstLayout.setAccessible(true);
mFirstLayout.set(this, true);
getAdapter().notifyDataSetChanged();
super.setCurrentItem(item);
} catch (Exception e) {
e.printStackTrace();
}
} public class MyFragmentPagerAdapter extends FragmentPagerAdapter { public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
} @Override
public Fragment getItem(int position) {
return mFragments == null ? null : mFragments.get(position);
} @Override
public int getCount() {
return mFragments == null ? 0 : mFragments.size();
}
}
}
}

使用 ViewPager 和 RadioGroup 封装的一个导航控件的更多相关文章

  1. 【完全开源】百度地图Web service API C#.NET版,带地图显示控件、导航控件、POI查找控件

    目录 概述 功能 如何使用 参考帮助 概述 源代码主要包含三个项目,BMap.NET.BMap.NET.WindowsForm以及BMap.NET.WinformDemo. BMap.NET 对百度地 ...

  2. 【转】【完全开源】百度地图Web service API C#.NET版,带地图显示控件、导航控件、POI查找控件

    [转][完全开源]百度地图Web service API C#.NET版,带地图显示控件.导航控件.POI查找控件 目录 概述 功能 如何使用 参考帮助 概述 源代码主要包含三个项目,BMap.NET ...

  3. 天津政府应急系统之GIS一张图(arcgis api for flex)讲解(四)地图导航控件模块

    config.xml文件的配置如下: <widget left="10" top="50" config="widgets/Navigation ...

  4. 设计一个 iOS 控件

    转载自:http://blog.csdn.net/zhangao0086/article/details/45622875 代码的等级:可编译.可运行.可测试.可读.可维护.可复用 前言 一个控件从外 ...

  5. openlayers4 入门开发系列之地图导航控件篇(附源码下载)

    前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...

  6. Android 一个日历控件的实现代码

    转载  2017-05-19   作者:Othershe   我要评论 本篇文章主要介绍了Android 一个日历控件的实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看 ...

  7. 3ds Max 中的导航控件SteeringWheels入门介绍

    介绍 软件环境:3d Max2015 SteeringWheels 3D导航控件也可以说是“追踪菜单”,通过它们可以使用户从单一的工具访问不同的2D和3D导航工具.SteeringWheels可分成多 ...

  8. .net验证控件,导航控件

    一.客户端验证(用户体验,减少服务器端压力) 二.服务器端验证(防止恶意攻击,客户端js很容易被绕过) 验证控件:RequiredFieldValidator:字段必填:RangeValidator: ...

  9. Add an Item to the Navigation Control 将项目添加到导航控件

    In this lesson, you will learn how to add an item to the navigation control. For this purpose, the N ...

随机推荐

  1. 执行shell脚本的几种方法及区别

    执行shell脚本的几种方法及区别 http://blog.csdn.net/lanxinju/article/details/6032368 (认真看) 注意:如果涉及到脚本之间的调用一定要用 . ...

  2. 使用dd工具对磁盘RAID5和10进行I/O性能测试

    很多情况下大家在对于理论深信不疑,理论是有前提条件的,不是所有的情况下都是正确的.恰逢公司有服务器,故进行了磁盘性能测试,当然测试的结果也只是顺序I/O性能测试(dd机制决定的). 前提条件:(DEL ...

  3. WeUI—微信官方UI库

    WeUI 为微信 Web 服务量身设计 概述 WeUI是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信 Web 开发量身设计,可以令用户的使用感知更加统一.包含button.cell ...

  4. win2003下全自动快速安装php+mysql套件

    导读:Windows 2003下一键快速安装PHP和MySql的安装包 场景:wind2003 32位 php5.2 1.下载php+mysql套件 地址1 http://pan.baidu.com/ ...

  5. VMware Workstation linux 问题

    1.can't find  /mnt/cdrom in etc/fstab or /etc/mtab mkdir /mnt/cdrom 2.80端口被占 一.查看哪些端口被打开 netstat -an ...

  6. Power Bi的优势 特色功能

    Power-BI可以让决策者不再依赖他人,就可及时.准确(没有人为加工,自然是最准确的)的得到各种关键经营数据: Power-BI不仅仅是让报表自动生成,而是完全改变了获取经营数据的方式,它可以直观的 ...

  7. 使用NSURLSession请求需要AD认证的HTTPS服务器

    关键代码:使用后台下载PDF文件 - (void)startDownloadPDF{ NSURLSession *session = [self session]; NSString *downloa ...

  8. IIS URL Rewrite redirect from one Domain to another

    IIS URL Rewrite enables Web administrators to create powerful rules to implement URLs that are easie ...

  9. Oracle Flashback Technologies - 估算不同时间段闪回日志的产生量

    Oracle Flashback Technologies - 估算不同时间段闪回日志的产生量 v$flashback_database_stat监控闪回数据的i/o开销的统计信息,根据之前的系统负载 ...

  10. define 实例

    // ----------------------------------------------define------------------------------------- // #def ...