教你轻松自界说ViewPagerIndicator-Android-优质IT资源分享社区

admin
管理员
管理员
  • UID1
  • 粉丝26
  • 关注4
  • 发帖数581
  • 社区居民
  • 忠实会员
  • 原创写手
阅读:144回复:0

  教你轻松自界说ViewPagerIndicator

楼主#
更多 发布于:2016-05-30 22:02


ViewPagerIndicator集成分页指示器,本来即是标题栏和ViewPager的联动作用,咱们先看一下作用图直观了解:(图侵删)

这篇文章将会教咱们怎样简略快速地制造自个的ViewPagerIndicator,一起阐明制造思路,让咱们能够容易的拓展和定制自个想要的作用。
由于文章的首要意图在于介绍全体思路,所以完成的界面作用也许不是很美观,不过咱们看过这篇文章今后,必定能够自个修正出美观的作用的。
话不多说,先来阐明全体思路。
对比上图,关于整个控件而言,明显下面显现内容的,是一个ViewPager,经过ViewPager咱们容易的得到翻页的作用,那么难点在于上面的标题导航栏,总的来说咱们要完成三点:
1,运用ViewPager翻页的时分,导航栏相应的标题会有改动(例如上图的蓝色的下划线,或者布景颜色的改动),来提示用户,如今是哪个标题下的内容
2,点击导航栏标题,ViewPager会翻到对应页,别的当咱们点击某个title时,咱们期望整个视图能够移动到以这个title为基地。
3,当导航栏的标题过多,超出屏幕宽度,咱们能够滑动导航栏找到后边的别的标题
要完成上面三个作用,我先来说第三个的完成
我运用HorizontalScrollView来完成,HorizontalScrollView能够水平拖动,假设HorizontalScrollView里边包括着一系列的TextView,这个款式不即是我想要的标题栏的作用吗?
由于HorizontalScrollView承继自FrageLayout,所以里边只能包括一个子控件,通常是LinearLayout,然后再让LinearLayout去包括TextView就能够了
别的还要讲HorizontalScrollView的HorizontalScrollBarEnabled设置为false,用于躲藏它本来的水平方向的滚动条
OK,看起来咱们第三个疑问解决了
如今来思考第一个疑问,要title跟从ViewPager改动,咱们很天然想到要去监听ViewPager的翻页事情,运用ViewPager.OnPageChangeListener,由于title的数目跟ViewPager中Fragement的数目相同多,翻到那个,咱们将关于index的title(也即是Textview)的布景变色就能够了
由于ViewPager.OnPageChangeListener的onPageSelected(int
position)中的参数position会为咱们供给这个index
OK,第一个疑问形似也没有那么难。
如今来思考第二个疑问,这儿触及两个滑动。
一个是ViewPager的滑动,正如咱们上面所说,TextView和ViewPager中Fragement一一对应
为了响应点击,明显我要每个TextView设置一个OnClickListener
但是TextView怎样知道自个的index呢?TextView自身是没有这个特点的,咱们能够承继TextView,然后增加一个index特点不就完了吗?
有了index,咱们在onclick办法里边,调用ViewPager的setCurrentItem(item)办法,就能够让ViewPager滑动到准确的方位
上面所说动画作用是ViewPager自带的,但是第二个滑动,即是HorizontalScrollView自身的滑动,HorizontalScrollView咱们能够手动滑动,但是怎样样才能让它自动滑到咱们需求的方位呢?
HorizontalScrollView供给了一个smoothScrollTo(int x, int
y)办法,运用这个办法,咱们能够将HorizontalScrollView滑动到恣意方位。
疑问使咱们怎样断定这个方位,由于每个TextView里边的文字数目也许不相同,意味着TextView的宽度各不相同,这么要怎样核算方位呢?
咱们能够运用getLeft()办法取得方针TextView间隔左面的长度,这么就不必管之前的TextView的宽度了,由于getLeft()相当于取得了它们的和,但是移动到getLeft()就超过了,咱们期望它移动到中心方位,那么getLeft()还有减去(HorizontalScrollView.getWidth()-TextView.getWidth())/2
至于为何这么算,咱们不理解的话,能够看图:我不再做过多解释

核算出smoothScrollTo()的方位今后,调用这个函数就好了,这么就完成了标题栏和ViewPager的联动作用。
原理解说到这儿,下面咱们来直接看代码。
先来看构造函数和相关特点
public class MyIndicator extends
HorizontalScrollView implements ViewPager.OnPageChangeListener{     private
ViewPager mViewPager;     private MyLinearLayout myLinearLayout;    
ViewPager.OnPageChangeListener mListener;     public MyIndicator(Context
context) {          super(context);          init(context);     }     public
MyIndicator(Context context, AttributeSet attrs) {          super(context,
attrs);          init(context);     }     public MyIndicator(Context context,
AttributeSet attrs, int defStyle) {          super(context, attrs, defStyle);  
       init(context);     }     private void init(Context mcontext){        
 setHorizontalScrollBarEnabled(false);//躲藏自带的滚动条          //增加linearLayout      
   myLinearLayout = new MyLinearLayout(mcontext);        
 myLinearLayout.setOrientation(LinearLayout.HORIZONTAL);        
 addView(myLinearLayout, new ViewGroup.LayoutParams(WRAP_CONTENT,
MATCH_PARENT));     }}
从上面的代码咱们能够看到,我承继HorizontalScrollView来自界说了一个控件,这个控件即是咱们上面说的导航栏,并且躲藏了它的滚动条
别的咱们完成了ViewPager.OnPageChangeListener接口,由于咱们要监听ViewPager的滑页做法,从而去改动导航栏的状况
所以咱们也能够看到,MyIndicator持有ViewPager的引证
但是有人会问,已然咱们为ViewPager设置了为MyIndicator,假如咱们还想要监听ViewPager怎样办呢?
所以咱们为MyIndicator供给了一个办法
public void
setOnPageChangeListener(ViewPager.OnPageChangeListener listener){      mListener
= listener;}
这么就能够为ViewPager设置了,而这个listener的调用,需求咱们在MyIndicator完成的ViewPager.OnPageChangeListener接口的办法的终究自动调用
也即是这么写:
@Overridepublic void onPageScrolled(int position,
float positionOffset, int positionOffsetPixels) {     if(mListener!=null)
mListener.onPageScrolled(position,positionOffset,positionOffsetPixels);}@Overridepublic
void onPageSelected(int position) {     setCurrentItem(position);    
if(mListener!=null) mListener.onPageSelected(position);}@Overridepublic void
onPageScrollStateChanged(int state) {     if(mListener!=null)
mListener.onPageScrollStateChanged(state);}
看完了初始化的作业,咱们能够看看怎样运用这个MyIndicator
首先在xml规划文件里边,很简略,直接运用

然后在Activity里边这么
@Overrideprotected void onCreate(Bundle
savedInstanceState) {       super.onCreate(savedInstanceState);      
setContentView(R.layout.activity_main);       ViewPager pager =
(ViewPager)findViewById(R.id.pager);       MyIndicator indicator =
(MyIndicator)findViewById(R.id.indicator);      
indicator.setViewPager(pager);}
经过一个setViewPager()办法使MyIndicator持有ViewPager的引证就能够了
OK,接下来继续看MyIndicator怎样写,看setViewPager()办法
public void setViewPager(ViewPager viewPager){    
setViewPager(viewPager,0);}public void setViewPager(ViewPager viewPager,int
initPos){     if (mViewPager == viewPager) {           return;     }     if
(mViewPager != null) {           mViewPager.setOnPageChangeListener(null);     }
    final PagerAdapter adapter = viewPager.getAdapter();     if (adapter ==
null) {           throw new IllegalStateException("ViewPager does not have
adapter instance.");     }     mViewPager = viewPager;    
viewPager.setOnPageChangeListener(this);     notifyDataSetChanged();    
setCurrentItem(initPos);}
在上面的代码中咱们能够看到,咱们查看了ViewPager的Adapter是不是为空,假如是要抛出反常
阐明咱们必须在调用setViewPager()之前为ViewPager设置Adapter
为何呢?由于导航栏的标题数目跟ViewPager的页面数目是相同的,而FragmentPagerAdapter里边的getCount()办法返回了这个数目,假如没有设置Adapter
MyIndicator就不知道怎样制作导航栏了,由于连标题数目都不清楚
关于Adapter,咱们能够写一个简略的,例如
class GoogleMusicAdapter extends
FragmentPagerAdapter {      public GoogleMusicAdapter(FragmentManager fm) {    
       super(fm);      }      @Override      public Fragment getItem(int
position) {           return TestFragment.newInstance(CONTENT[position %
CONTENT.length]);      }      @Override      public CharSequence
getPageTitle(int position) {           return CONTENT[position %
CONTENT.length].toUpperCase();      }      @Override      public int getCount()
{           return CONTENT.length;      }}
其间TestFragment是这么的
public final class TestFragment extends Fragment {
    private static final String KEY_CONTENT = "TestFragment:Content";     public
static TestFragment newInstance(String content) {           TestFragment
fragment = new TestFragment();           StringBuilder builder = new
StringBuilder();           for (int i = 0; i < 20; i++) {                
 builder.append(content).append(" ");           }          
builder.deleteCharAt(builder.length() - 1);           fragment.mContent =
builder.toString();           return fragment;     }     private String mContent
= "???";     @Override     public void onCreate(Bundle savedInstanceState) {    
      super.onCreate(savedInstanceState);           if ((savedInstanceState !=
null) && savedInstanceState.containsKey(KEY_CONTENT)) {                
mContent = savedInstanceState.getString(KEY_CONTENT);           }     }    
@Override     public View onCreateView(LayoutInflater inflater, ViewGroup
container, Bundle savedInstanceState) {           TextView text = new
TextView(getActivity());           text.setGravity(Gravity.CENTER);          
text.setText(mContent);           text.setTextSize(20 *
getResources().getDisplayMetrics().density);           text.setPadding(20, 20,
20, 20);           LinearLayout layout = new LinearLayout(getActivity());      
    layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));           layout.setGravity(Gravity.CENTER);        
  layout.addView(text);           return layout;     }     @Override     public
void onSaveInstanceState(Bundle outState) {        
 super.onSaveInstanceState(outState);          outState.putString(KEY_CONTENT,
mContent);     }}
本来即是一个 创立Fragment的工具类
终究在Activity修正一下
@Overrideprotected void onCreate(Bundle
savedInstanceState) {      super.onCreate(savedInstanceState);    
 setContentView(R.layout.activity_main);      FragmentPagerAdapter adapter = new
GoogleMusicAdapter(getSupportFragmentManager());      ViewPager pager =
(ViewPager)findViewById(R.id.pager);      pager.setAdapter(adapter);    
 MyIndicator indicator = (MyIndicator)findViewById(R.id.indicator);    
 indicator.setViewPager(pager);}
回过头来看setViewPager()办法,然后即是调用了两个函数,首先是notifyDataSetChanged()
private void notifyDataSetChanged(){    
 myLinearLayout.removeAllViews();      PagerAdapter mAdapter =
mViewPager.getAdapter();      int count = mAdapter.getCount();      for(int
i=0;i<count;i++){            addTab(i,mAdapter.getPageTitle(i));      }    
 requestLayout();}private void addTab(int index,CharSequence text) {    
 TabView tabView = new TabView(getContext());      tabView.index = index;    
 tabView.setFocusable(true);      tabView.setOnClickListener(mTabClickListener);
     tabView.setText(text);      tabView.setTextSize(30);    
 tabView.setPadding(20,0,20,0);      myLinearLayout.addView(tabView);}
这个函数本来即是起到增加标题的作用
咱们经过Adapter取得了数目,然后逐一调用addTab()将标题栏增加进LinearLayout
有人会问myLinearLayout是啥,如今在MyIndicator里边本来即是一个LinearLayout,我独立出来是为了咱们今后便利拓展,代码如下
public class MyLinearLayout extends LinearLayout {
    public MyLinearLayout(Context context) {          super(context);        
 setWillNotDraw(false);     }}
然后来看addTab()做了啥,望文生义,即是增加tab,前面原理剖析的时分,咱们现已说过tab本来是TextView,但是要符号index,所以咱们要承继TextView自界说一个控件
private class TabView extends TextView {      
public int index;       public TabView(Context context,int index){            
this(context);             this.index = index;       }       public
TabView(Context context) {             super(context);       }}
能够看到,本来仅仅为textView增加了Index特点
到此为止,还不触及动画作用,但是咱们在模拟器上看,就能够看到标题栏的出现,并且标题的数目,会跟你ViewPager中Fragment数目相同
下面来议论动画作用的完成
上面咱们记住,setViewPager()办法里边,还有一个setCurrentItem()办法,别的onPageSelected()里边也有调用这个办法
本来这个办法即是来完成换页的动态作用的,onPageSelected()里边调用,能够在viewPager滑动的时分换页
public void setCurrentItem(int item) {     if
(mViewPager == null) {           throw new IllegalStateException("ViewPager has
not been bound.");     }     int mSelectedTabIndex = item;    
mViewPager.setCurrentItem(item);     final int tabCount =
myLinearLayout.getChildCount();     for (int i = 0; i < tabCount; i++)
{//遍历标题,改动选中的布景           final View child = myLinearLayout.getChildAt(i);      
    final boolean isSelected = (i == item);          
child.setSelected(isSelected);           if (isSelected) {                
child.setBackgroundColor(Color.RED);                 animateToTab(item);//动画作用  
        }else{                 child.setBackgroundColor(Color.TRANSPARENT);    
      }     }}
本来这个办法也很简略,首先完成ViewPager的滑动,只要调用ViewPager的setCurrentItem()办法就好了
接下来遍历每个标题,使选中的标题布景色成为赤色,别的布景色成为蓝色
但是这么还不行,咱们还有标题栏自动滑动,使标题处于正中心
所以咱们又了aniateToTab()办法
如下
private Runnable mTabSelector;     private void
animateToTab(final int position) {           final View tabView =
myLinearLayout.getChildAt(position);/获取方针标题栏对象           if (mTabSelector !=
null) {                 removeCallbacks(mTabSelector);           }          
mTabSelector = new Runnable() {           public void run() {              
 final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) /
2;//核算要滑动到的方位                smoothScrollTo(scrollPos, 0);              
 mTabSelector = null;           }     };     post(mTabSelector);//在主线程履行动画}
和一开始就阐明得原理相同,咱们核算出来要smoothScrollTo的终究方位,然后调用这个办法就好了
只要写在runnable里边,是为了确保在主线程调用
OK,到此为止,咱们就完成了滑动ViewPager,标题栏也会滑动的作用了,不信咱们如今能够测验一下自个的代码
接下来即是点击标题,也会自动滑动,为了让TextView能点击,我为每个TextView都设置了OnClickListener
private final OnClickListener mTabClickListener =
new OnClickListener() {      public void onClick(View view) {           TabView
tabView = (TabView)view;           final int oldSelected =
mViewPager.getCurrentItem();           final int newSelected = tabView.index;  
        setCurrentItem(newSelected);      }};
里边更简略,即是取得方针标题栏的index,然后调用setCurrentItem()就能够了
这么就完成了点击滑动的作用,点击标题栏,Viewpager也会跟着翻页哦
整个控件就说完了,假如咱们事前理解了我的思路,看起代码来应当很流畅
终究贴出MyIndicator的完好代码,咱们能够随意改造,完成自个需求的作用啊!
public class MyIndicator extends
HorizontalScrollView implements ViewPager.OnPageChangeListener{      private
ViewPager mViewPager;      private MyLinearLayout myLinearLayout;    
 ViewPager.OnPageChangeListener mListener;      private final OnClickListener
mTabClickListener = new OnClickListener() {           public void onClick(View
view) {                TabView tabView = (TabView)view;                final int
oldSelected = mViewPager.getCurrentItem();                final int newSelected
= tabView.index;                setCurrentItem(newSelected);           }      };
     public MyIndicator(Context context) {            super(context);          
 init(context);      }      public MyIndicator(Context context, AttributeSet
attrs) {            super(context, attrs);            init(context);      }    
 public MyIndicator(Context context, AttributeSet attrs, int defStyle) {        
   super(context, attrs, defStyle);            init(context);      }    
 private void init(Context mcontext){          
 setHorizontalScrollBarEnabled(false);//躲藏自带的滚动条            //增加linearLayout    
       myLinearLayout = new MyLinearLayout(mcontext);          
 myLinearLayout.setOrientation(LinearLayout.HORIZONTAL);          
 addView(myLinearLayout, new ViewGroup.LayoutParams(WRAP_CONTENT,
MATCH_PARENT));      }       public void setViewPager(ViewPager viewPager){    
        setViewPager(viewPager,0);       }       public void
setViewPager(ViewPager viewPager,int initPos){             if (mViewPager ==
viewPager) {                   return;             }             if (mViewPager
!= null) {                   mViewPager.setOnPageChangeListener(null);          
  }             final PagerAdapter adapter = viewPager.getAdapter();            
if (adapter == null) {                   throw new
IllegalStateException("ViewPager does not have adapter instance.");            
}             mViewPager = viewPager;            
viewPager.setOnPageChangeListener(this);             notifyDataSetChanged();    
        setCurrentItem(initPos);      }      private void
notifyDataSetChanged(){             myLinearLayout.removeAllViews();            
PagerAdapter mAdapter = mViewPager.getAdapter();             int count =
mAdapter.getCount();             for(int i=0;i<count;i++){                  
addTab(i,mAdapter.getPageTitle(i));             }             requestLayout();  
   }      private void addTab(int index,CharSequence text) {            TabView
tabView = new TabView(getContext());            tabView.index = index;          
 tabView.setFocusable(true);          
 tabView.setOnClickListener(mTabClickListener);          
 tabView.setText(text);            tabView.setTextSize(30);          
 tabView.setPadding(20,0,20,0);            myLinearLayout.addView(tabView);    
 }      public void setCurrentItem(int item) {            if (mViewPager ==
null) {                   throw new IllegalStateException("ViewPager has not
been bound.");            }            int mSelectedTabIndex = item;          
 mViewPager.setCurrentItem(item);            final int tabCount =
myLinearLayout.getChildCount();            for (int i = 0; i < tabCount; i++)
{//遍历标题,改动选中的布景                  final View child =
myLinearLayout.getChildAt(i);                  final boolean isSelected = (i ==
item);                  child.setSelected(isSelected);                  if
(isSelected) {                        child.setBackgroundColor(Color.RED);      
                 animateToTab(item);//动画作用                  }else{              
         child.setBackgroundColor(Color.TRANSPARENT);                  }        
  }     }     private Runnable mTabSelector;          private void
animateToTab(final int position) {                final View tabView =
myLinearLayout.getChildAt(position);                if (mTabSelector != null) {
                     removeCallbacks(mTabSelector);                }            
   mTabSelector = new Runnable() {                      public void run() {    
                      final int scrollPos = tabView.getLeft() - (getWidth() -
tabView.getWidth()) / 2;                           smoothScrollTo(scrollPos, 0);
                          mTabSelector = null;                     }            
  };               post(mTabSelector);         }          public void
setOnPageChangeListener(ViewPager.OnPageChangeListener listener){              
 mListener = listener;          }          @Override          public void
onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  
             if(mListener!=null)
mListener.onPageScrolled(position,positionOffset,positionOffsetPixels);        
 }          @Override          public void onPageSelected(int position) {      
         setCurrentItem(position);                if(mListener!=null)
mListener.onPageSelected(position);          }          @Override        
 public void onPageScrollStateChanged(int state) {              
 if(mListener!=null) mListener.onPageScrollStateChanged(state);          }      
   private class TabView extends TextView {                public int index;    
           public TabView(Context context,int index){                    
 this(context);                      this.index = index;                }      
         public TabView(Context context) {                      super(context);
               }          }   }








优质IT资源分享社区为你提供此文。
站有大量优质android教程视频,资料等资源,包含android基础教程,高级进阶教程等等,教程视频资源涵盖传智播客,极客学院,达内,北大青鸟,猎豹网校等等IT职业培训机构的培训教学视频,价值巨大。欢迎点击下方链接查看。

android教程视频
优质IT资源分享社区(www.itziyuan.top)
一个免费,自由,开放,共享,平等,互助的优质IT资源分享网站。
专注免费分享各大IT培训机构最新培训教学视频,为你的IT学习助力!

!!!回帖受限制请看点击这里!!!
!!!资源失效请在此版块发帖说明!!!

[PS:按 CTRL+D收藏本站网址~]

——“优质IT资源分享社区”管理员专用签名~

本版相似帖子

游客