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目录下找。
- SlidingTabColors——viewpager和自定义导航栏
- 初学自定义view实现viewpager导航栏
- Android——ViewPager和底部导航的配合
- 自定义ViewPager的导航indecator(非常实用和主流)
- 实例—ViewPager+RadioGroup实现底部导航栏和页面的滑动
- Fragment和ViewPager实现底部导航栏
- TabLayout和ViewPager打造导航栏
- 底部导航栏(自定义View+ViewPager实现) android项目详解
- Android自定义控件---导航栏SlideTab(Fragment+ViewPager)
- android仿微信底部导航栏+viewPager+自定义view
- 自定义ViewPagerIndicator---炫酷的导航栏指示器+ViewPager+Fragment
- 自定义导航栏与ViewPager的结合使用
- 自定义顶端顶部导航栏(可配合ViewPager使用)
- Android自定义组件系列【10】——随ViewPager滑动的导航条
- Android底部导航栏——FragmentTabHost+ViewPager+Fragment
- 自定义导航栏和状态栏
- ViewPager导航栏
- ViewPager添加导航栏
- xp系统Java 7环境变量配置及eclipse使用
- 用程序来控制一个网页,实现自动输入等操作
- @Override标签
- Python学习笔记___初识Python
- 小游戏------锅打灰太狼
- SlidingTabColors——viewpager和自定义导航栏
- HDFS写数据过程
- interrupted() 和 isInterrupted() 的区别
- python-基础
- 【Unity3D】本地数据加密_2
- LinearLayout
- HDU1290 水题
- wordcount运行过程
- 日常记录——关于数组下标计算的一点心得