SlidingTabColors——viewpager和自定义导航栏

来源:互联网 发布:数据加密算法有哪些 编辑:程序博客网 时间:2024/05/22 10:50

SlidingTabColors

之前阅读过Android Samples中UI的部分,过后发现很多知识点都忘了。今天开始把看过的东西都整理记录一下,从小事做起吧。与君共勉。

源代码在/android-23/ui/SlidingTabsColors下。

  • 使用ViewPager滑动界面
  • Canvas绘图
  • Fragment的使用
  • 动态添加View
  • ScrollView的使用

目录

  • SlidingTabColors
      • 目录
    • 数据的交互
      • MainActivity
      • ContentFragment
      • SlidingTabsColorsFragment
    • 自定义的View
      • SlidingTabLayout
      • SlidingTabStrip
      • 实现效果


数据的交互

MainActivity

源码中主界面包含两个Fragment,上面的主要功能是打Log,下面的Fragment是核心功能的实现。

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();SlidingTabsColorsFragment fragment = new SlidingTabsColorsFragment();transaction.replace(R.id.sample_content_fragment, fragment);transaction.commit();

ContentFragment

此类为ViewPager中Adapter的Item。

public class ContentFragment extends Fragment {    //使用Bundle传递数据。    public static ContentFragment newInstance(CharSequence title, int indicatorColor,            int dividerColor) {        Bundle bundle = new Bundle();        bundle.putCharSequence(KEY_TITLE, title);        bundle.putInt(KEY_INDICATOR_COLOR, indicatorColor);        bundle.putInt(KEY_DIVIDER_COLOR, dividerColor);        ContentFragment fragment = new ContentFragment();        fragment.setArguments(bundle);        return fragment;    }    //该Fragment中包含三个TextView,分别显示文字,指示器颜色,分割线颜色。    @Override    public void onViewCreated(View view, Bundle savedInstanceState) {        super.onViewCreated(view, savedInstanceState);        Bundle args = getArguments();        if (args != null) {            TextView title = (TextView) view.findViewById(R.id.item_title);            title.setText("Title: " + args.getCharSequence(KEY_TITLE));            int indicatorColor = args.getInt(KEY_INDICATOR_COLOR);            TextView indicatorColorView = (TextView) view.findViewById(R.id.item_indicator_color);            indicatorColorView.setText("Indicator: #" + Integer.toHexString(indicatorColor));            indicatorColorView.setTextColor(indicatorColor);            int dividerColor = args.getInt(KEY_DIVIDER_COLOR);            TextView dividerColorView = (TextView) view.findViewById(R.id.item_divider_color);            dividerColorView.setText("Divider: #" + Integer.toHexString(dividerColor));            dividerColorView.setTextColor(dividerColor);        }    }}

SlidingTabsColorsFragment

在SlidingTabsColorsFragment中添加ViewPager,而ViewPager的中的内容是ContentFragment,由下面这个类的createFragment()方法提供提供。

static class SamplePagerItem {        private final CharSequence mTitle;        private final int mIndicatorColor;        private final int mDividerColor;        SamplePagerItem(CharSequence title, int indicatorColor, int dividerColor) {            mTitle = title;            mIndicatorColor = indicatorColor;            mDividerColor = dividerColor;        }        /**         * @return A new {@link Fragment} to be displayed by a {@link ViewPager}         * 获取ContentFragment()的方法         */        Fragment createFragment() {            return ContentFragment.newInstance(mTitle, mIndicatorColor, mDividerColor);        }        /**         * @return the title which represents this tab. In this sample this is used directly by         * {@link android.support.v4.view.PagerAdapter#getPageTitle(int)}         * ViewPager中的文本内容         */        CharSequence getTitle() {            return mTitle;        }        /**         * @return the color to be used for indicator on the {@link SlidingTabLayout}         * ScrollView中下面指示器的颜色         */        int getIndicatorColor() {            return mIndicatorColor;        }        /**         * @return the color to be used for right divider on the {@link SlidingTabLayout}         * ScrollView中分割线的颜色         */        int getDividerColor() {            return mDividerColor;        }    }
//使用ArrayList创建几个ContentFragmentprivate List<SamplePagerItem> mTabs = new ArrayList<SamplePagerItem>();
//选择FragmentPagerAdapter作为ViewPager的Adapter。class SampleFragmentPagerAdapter extends FragmentPagerAdapter {        SampleFragmentPagerAdapter(FragmentManager fm) {            super(fm);        }//获取item,类型为ContentFragment        @Override        public Fragment getItem(int i) {            return mTabs.get(i).createFragment();        }        @Override        public int getCount() {            return mTabs.size();        }//显示内容文字        @Override        public CharSequence getPageTitle(int position) {            return mTabs.get(position).getTitle();        }    }
    mViewPager = (ViewPager) view.findViewById(R.id.viewpager);    mViewPager.setAdapter(new SampleFragmentPagerAdapter(getChildFragmentManager()));

自定义的View

滑动条需要手动实现,原理是在HorizontalScrollView中添加一个LinearLayout,再在LinearLayout中添加几个TextView,当然也可以是其他的ui控件。

SlidingTabLayout

SlidingTabLayout继承自HorizontalScrollView

public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        // Disable the Scroll Bar        setHorizontalScrollBarEnabled(false);        // Make sure that the Tab Strips fills this View        setFillViewport(true);    //首先添加一个LinearLayout        mTabStrip = new SlidingTabStrip(context);        addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);    }

前面ViewPager的Item有几个,那么在LinearLayout中也添加几个TextView。

private void populateTabStrip() {        final PagerAdapter adapter = mViewPager.getAdapter();        final View.OnClickListener tabClickListener = new TabClickListener();        for (int i = 0; i < adapter.getCount(); i++) {            View tabView = null;            TextView tabTitleView = null;            if (tabView == null) {                tabView = createDefaultTabView(getContext());            }            tabTitleView.setText(adapter.getPageTitle(i));            //给TextView添加点击事件,点击textview,ViewPager调转到对应id的Item            tabView.setOnClickListener(tabClickListener);            mTabStrip.addView(tabView);        }    }//刚初始化时,ScrollView显示在第一个item的位置@Override    protected void onAttachedToWindow() {        super.onAttachedToWindow();        if (mViewPager != null) {            scrollToTab(mViewPager.getCurrentItem(), 0);        }    }/*需要注意scrollToTab()方法中的scrollTo(x,y)方法,该方法在ScrollView中,其中的两个参数指的是scrollView的偏移量。scrollView第一次在界面上显示时,它的左边应该是贴着手机的左边的(不一定在手机的左上角),View的左上角的坐标为(0,0),假如我们调用scrollTo(x,y)方法,那么整个ScrollView会移动(-x,-y)的距离,即scrollView上的(x,y)点会移动到刚刚(0,0)的位置。--我的理解是这样的。*/    private void scrollToTab(int tabIndex, int positionOffset) {        final int tabStripChildCount = mTabStrip.getChildCount();        if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {            return;        }        View selectedChild = mTabStrip.getChildAt(tabIndex);        if (selectedChild != null) {/*targetScrollX就是ScrollView将要将要水平移动的位置,此处设置的是比positionOffset要小一些。比如Viewpager移动到了下一个,则positionOffset为一个TextView的宽度,但是我们让他移动positionOffset-mTitleOffset个宽度,那么就可以显示上一个TextView的一部分了。*/            int targetScrollX = selectedChild.getLeft() + positionOffset;            if (tabIndex > 0 || positionOffset > 0) {                // If we're not at the first child and are mid-scroll, make sure we obey the offset                targetScrollX -= mTitleOffset;            }            scrollTo(targetScrollX, 0);        }    }//添加ViewPagerListener,为了实现滑动ViewPager,指示器也跟着运动。    private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {        private int mScrollState;        @Override        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {            int tabStripChildCount = mTabStrip.getChildCount();           //position不能等于tabStripChildCount,后面要获取           //nextView,若等于,nextView为空。            if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {                return;            }//设置extraOffset,只是为了界面好看一些。            mTabStrip.onViewPagerPageChanged(position, positionOffset);            View selectedTitle = mTabStrip.getChildAt(position);            int extraOffset = (selectedTitle != null)                    ? (int) (positionOffset * selectedTitle.getWidth())                    : 0;            scrollToTab(position, extraOffset);        }//点击了TextView,ScrollView也要跟着改变,如果position>0,ScrollView会跟着滚动。        @Override        public void onPageSelected(int position) {            if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {                mTabStrip.onViewPagerPageChanged(position, 0f);                scrollToTab(position, 0);            }        }    }    //LinearLayout中textView的点击事件private class TabClickListener implements View.OnClickListener {        @Override        public void onClick(View v) {            for (int i = 0; i < mTabStrip.getChildCount(); i++) {            //获取点击的TextView的index,选择Viewpager相应的            //item                if (v == mTabStrip.getChildAt(i)) {                    mViewPager.setCurrentItem(i);                    return;                }            }        }    }

SlidingTabStrip

SlidingTabStrip继承自LinearLayout,即上面提到的LinearLayout,他是SlidingTabLayout的子View。我们在其中添加它的子View,也就是TextView,还需要在几个TextView的中间画分割线,最重要的是该View下方的指示器,他会跟随ViewPager的翻页移动到相应的位置。

//滑动Viewpager时调用了此方法,传入当前ViewPager的item //position和滑动百分比,调用invalidate()来刷新view。void onViewPagerPageChanged(int position, float positionOffset) {        mSelectedPosition = position;        mSelectionOffset = positionOffset;        invalidate();    }
@Override    protected void onDraw(Canvas canvas) {        final int height = getHeight();        final int childCount = getChildCount();//        设置分割线为半个TextView高度(随便一个值,好看就行)        final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height);        // Thick colored underline below the current selection        if (childCount > 0) {        //获取子View和它的宽高            View selectedTitle = getChildAt(mSelectedPosition);            int left = selectedTitle.getLeft();            int right = selectedTitle.getRight();            //通过一个interface获取当前positon对应SamplePagerItem的颜色。            int color = tabColorizer.getIndicatorColor(mSelectedPosition);            if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {                int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);                if (color != nextColor) {                    color = blendColors(nextColor, color, mSelectionOffset);                }                // Draw the selection partway between the tabs                View nextTitle = getChildAt(mSelectedPosition + 1);                //left = 当前View的左侧+(nextView左侧-当前View的左侧)×offset,右侧同理。                left = (int) (mSelectionOffset * nextTitle.getLeft() +                        (1.0f - mSelectionOffset) * left);                right = (int) (mSelectionOffset * nextTitle.getRight() +                        (1.0f - mSelectionOffset) * right);            }            mSelectedIndicatorPaint.setColor(color);            canvas.drawRect(left, height - mSelectedIndicatorThickness, right,                    height, mSelectedIndicatorPaint);        }        // Thin underline along the entire bottom edge        //在此View下方画一条线        canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);        // Vertical separators between the titles        for (int i = 0; i < childCount - 1; i++) {            View child = getChildAt(i);            mDividerPaint.setColor(tabColorizer.getDividerColor(i));            //共有childCount个TextView,中间有childCount-1个间隔,在其中画分割线。            canvas.drawLine(child.getRight(), separatorTop, child.getRight(),                    separatorTop + dividerHeightPx, mDividerPaint);        }    }

要实现滑动过程中指示器颜色渐变,只需要在onDraw()中更新painter的Color就可以。
颜色渐变的方法如下:

//获取两个颜色进行中和,实现颜色过度private static int blendColors(int color1, int color2, float ratio) {        final float inverseRation = 1f - ratio;        float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);        float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);        float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);        return Color.rgb((int) r, (int) g, (int) b);    }

实现效果

这里写图片描述 这里写图片描述 这里写图片描述

源码可百度android samples到ui目录下找。

0 0
原创粉丝点击