zoukankan      html  css  js  c++  java
  • 使用 ViewPager 和 RadioGroup 封装的一个导航控件

    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();
                }
            }
        }
    }
  • 相关阅读:
    火车头入库SQLSERVER时数据库配置的问题
    帝国CMS在封面、列表调用栏目别名的方法
    电子商务关键数字优化(线上部分,下)
    电子商务关键数字优化(线上部分,上)
    创业公司Celebrity Performance 评估名人影响力
    SQLautoReview
    互联网/电子商务数据分析师的十大误区
    Amazon Silk 你所不知道的在Kindle背后的大数据
    Nike可穿戴的大数据玩法
    [转]Decide.com是怎么做商品价格预测的
  • 原文地址:https://www.cnblogs.com/Westfalen/p/5463695.html
Copyright © 2011-2022 走看看