Android实现自定义引导页,玩转ViewPager

LeandroSeal 8年前
   <h2>ViewPager简介:</h2>    <p>ViewPager(android.support.v4.view.ViewPager)是android扩展包v4包中的类,这个类可以让用户左右切换当前的view,实现滑动切换的效果。</p>    <p>注意:</p>    <p>ViewPager类直接继承了ViewGroup类,也就是说它和我们经常打交道的LinearLayout一样,都是一个容器,需要在里面添加我们想要显示的内容。</p>    <p>ViewPager类需要一个PagerAdapter适配器类给它提供数据,这个和ListView类似。</p>    <h2>ViewPager基础使用</h2>    <p>具体步骤:</p>    <p>1.在布局文件里加入</p>    <pre>  <code class="language-java"><android.support.v4.view.ViewPager          android:id="@+id/in_viewpager"          android:layout_width="match_parent"          android:layout_height="match_parent">      </android.support.v4.view.ViewPager></code></pre>    <p>2.在Activity中加载要显示的Views,通过动态加载布局得到一个个View</p>    <pre>  <code class="language-java">mViewList = new ArrayList<View>();          LayoutInflater lf = getLayoutInflater().from(MainActivity.this);          View view1 = lf.inflate(R.layout.we_indicator1, null);          View view2 = lf.inflate(R.layout.we_indicator2, null);          View view3 = lf.inflate(R.layout.we_indicator3, null);          mViewList.add(view1);          mViewList.add(view2);          mViewList.add(view3);</code></pre>    <p>3.自定义PagerAdapter,以便将步骤2中的Views数据加载到ViewPager容器中</p>    <pre>  <code class="language-java">public class ViewPagerAdatper extends PagerAdapter {      private List<View> mViewList ;        public ViewPagerAdatper(List<View> mViewList ) {          this.mViewList = mViewList;      }        @Override      public int getCount() {          return mViewList.size();      }        @Override      public boolean isViewFromObject(View view, Object object) {          return view==object;      }        @Override      public Object instantiateItem(ViewGroup container, int position) {          container.addView(mViewList.get(position));          return mViewList.get(position);      }        @Override      public void destroyItem(ViewGroup container, int position, Object object) {          container.removeView(mViewList.get(position));      }  }</code></pre>    <p>4.将ViewPager和自定义的PagerAdapter关联起来</p>    <pre>  <code class="language-java">mIn_vp.setAdapter(new ViewPagerAdatper(mViewList));</code></pre>    <p>通过简单使用ViewPager,得到的展示效果,仅仅支持左右滑动,效果比较单一。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e2033258c556269f3e988a6f3767f26e.gif"></p>    <h2>ViewPager进阶使用——实现跟随式小圆点效果</h2>    <p>效果图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/aac0ca3e1dd855f1602a8521d4a16ec4.gif"></p>    <p>步骤:</p>    <p>1.添加小圆点</p>    <p>在布局中的设置如下:</p>    <pre>  <code class="language-java"><RelativeLayout          android:id="@+id/rl_dots"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_alignParentBottom="true"          android:layout_centerHorizontal="true"          android:layout_marginBottom="60dp">            <LinearLayout              android:id="@+id/in_ll"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:orientation="horizontal">          </LinearLayout>            <ImageView              android:id="@+id/iv_light_dots"              android:layout_width="wrap_content"              android:layout_height="wrap_content"              android:src="@drawable/light_dot"/>      </RelativeLayout></code></pre>    <p>随后在LinearLayout中动态添加3个小黑点,小白点默认覆盖在第一个小黑点的上面。</p>    <p>在Activity中的添加小黑点,代码如下:</p>    <pre>  <code class="language-java">private void addDots() {          mOne_dot = new ImageView(this);          mOne_dot.setImageResource(R.drawable.gray_dot);          LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);          layoutParams.setMargins(0, 0, 40, 0);          mIn_ll.addView(mOne_dot, layoutParams);          mTwo_dot = new ImageView(this);          mTwo_dot.setImageResource(R.drawable.gray_dot);          mIn_ll.addView(mTwo_dot, layoutParams);          mThree_dot = new ImageView(this);          mThree_dot.setImageResource(R.drawable.gray_dot);          mIn_ll.addView(mThree_dot, layoutParams);          setClickListener();        }</code></pre>    <p>2.获得两个点之间的距离</p>    <p>实现小白点动态跟随的思路是:根据页面的移动情况,通过设置小白点的 leftMargin 实现小红点的动态跟随。因此首要的是获得两个点之间的距离,根据页面移动到的位置,进行相应的运算。</p>    <p>需要注意的是:在onCreate()中直接获得小白点的左边距 getLeft()结果为0,这是因为View组件布局要在onResume回调后完成。</p>    <p>因此使用另一种方法:</p>    <pre>  <code class="language-java">mLight_dots.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {              @Override              public void onGlobalLayout() {                  //获得两个圆点之间的距离                  mDistance = mIn_ll.getChildAt(1).getLeft() - mIn_ll.getChildAt(0).getLeft();                 mLight_dots.getViewTreeObserver()                          .removeGlobalOnLayoutListener(this);              }          });</code></pre>    <p>在布局发生改变或者某个视图的可视状态发生改变时调用该事件。但此方法会被多次调用,因此需要在获取到视图的宽度和高度后执行 remove 方法移除该监听事件。</p>    <p>3.监听页面的移动情况</p>    <pre>  <code class="language-java">mIn_vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {              @Override              public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {                  //页面滚动时小白点移动的距离,并通过setLayoutParams(params)不断更新其位置                  float leftMargin = mDistance * (position + positionOffset);                  RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mLight_dots.getLayoutParams();                  params.leftMargin = (int) leftMargin;                  mLight_dots.setLayoutParams(params);               }                @Override              public void onPageSelected(int position) {                  //页面跳转时,设置小圆点的margin                  float leftMargin = mDistance * position;                  RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mLight_dots.getLayoutParams();                  params.leftMargin = (int) leftMargin;                  mLight_dots.setLayoutParams(params);              }                @Override              public void onPageScrollStateChanged(int state) {                }          });      }</code></pre>    <p>在页面移动过程中,根据mDistance * (position + positionOffset) 可以实时更新小白点的位置</p>    <p>这部分内容加入了一个新的功能 点击小黑点 可以直接跳转到对应的引导页面,具体逻辑就是在小黑点的点击事件中加入如下代码:</p>    <pre>  <code class="language-java">mIn_vp.setCurrentItem(1);</code></pre>    <p>在页面选择过程中,根据mDistance * position可以实时小红点的位置</p>    <p>4.跳转按钮的实现</p>    <p>具体逻辑:到引导页到达最后一页时,跳转到主页的按钮出现。其他情况为隐藏状态</p>    <p>因此可以在 onPageScrolled(int position, float positionOffset, int positionOffsetPixels) 和 onPageSelected(int position) 方法中加入如下代码:</p>    <pre>  <code class="language-java">if(position==2){                      mBtn_next.setVisibility(View.VISIBLE);                  }</code></pre>    <p>当按照从第一页到最后一页,然后点击按钮跳转到首页,则以上逻辑足够。</p>    <p>但当用户浏览到最后一页后再回转到前面感兴趣的页面,则会出现按钮依旧出现的情况,不符合要求。因此要完善逻辑,加入新的判断,逻辑如下:</p>    <pre>  <code class="language-java">if(position!=2&&mBtn_next.getVisibility()==View.VISIBLE){                      mBtn_next.setVisibility(View.GONE);                  }</code></pre>    <p>以上逻辑保证了按钮的正常显示,剩下的就可以具体操作,实现跳转到首页的逻辑。</p>    <h2>ViewPager进阶使用——自定义炫酷动画</h2>    <p>ViewPager自带了一个setPageTransformer用于设置切换动画~</p>    <p>setPageTransformer (boolean reverseDrawingOrder, PageTransformer transformer) 需要传入两个参数</p>    <p>第一个参数:如果为true,则表明自定义的pageTransformer需要 page view从后到前的顺序绘制,反之则为false。</p>    <p>第二个参数:传入一个自定义的pageTransformer对象</p>    <p>因此实现炫酷动画的关键点就在于:自定义pageTransformer</p>    <p>Google官方给我们展示了两个动画例子:DepthPageTransformer和ZoomOutPageTransformer,比较炫。我们就以Google官方的例子来学习自定义pageTransformer,以此为基础,我们可以自定义各种各样的动画实现效果。</p>    <p>1.PageTransformer中position解析</p>    <p>自定义PageTransformer只需要实现一个方法, transformPage(View page, float position) ,而这个方法实现的关键就是对position的理解。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/26800edfa4ad13618ab2ad8bc2a3acc0.png"></p>    <p>源码中的注释解释如下:</p>    <p>Apply the transformation to this page</p>    <p>position - Position of page relative to the current front-and-center position of the pager. 0 is front and center. 1 is one full page position to the right, and -1 is one page position to the left.</p>    <p>我们可以理解为:</p>    <p>0表示当前页面,是当前页面</p>    <p>-1表示左侧的页面,是左侧页面</p>    <p>1表示右侧的页面,是右侧页面</p>    <p>在用户滑动界面的时候,position是动态变化的,下面以左滑为例:</p>    <p>选中页面 position:0->-1</p>    <p>前一个item position:-1 -> -2</p>    <p>后一个item position:1 -> 0</p>    <p>但是当ViewPager设置pageMargin,设置两个页面之间的距离(通过调用viewPager.setPageMargin()方法设置)后,情况则不同。</p>    <p>如果你设置了pageMargin,前后页面的position需要分别加上(或减去,前减后加)一个偏移量(偏移量的计算方式为pageMargin / pageWidth)。</p>    <p>同样以左滑为例:</p>    <p>选中页面position:0->-1 - pageMargin / pageWidth</p>    <p>前一个item position:-1 - pageMargin / pageWidth -> -2 - pageMargin / pageWidth</p>    <p>后一个item position:1 + pageMargin / pageWidth -> 0</p>    <p>因此我们可以将position的值应用于setAlpha(), setTranslationX(), 或者 setScaleY()等等方法,从而实现自定义的动画效果。</p>    <p>2.实现 transformPage(View page, float position) 方法</p>    <pre>  <code class="language-java">public class DepthPageTransformer implements ViewPager.PageTransformer {      private static final float MIN_SCALE = 0.75f;      @Override      public void transformPage(View page, float position) {          int pageWidth = page.getWidth();          if (position < -1) { // [-Infinity,-1)              // 页面远离左侧页面              page.setAlpha(0);          } else if (position <= 0) { // [-1,0]              // 页面在由中间页滑动到左侧页面 或者 由左侧页面滑动到中间页              page.setAlpha(1);              page.setTranslationX(0);              page.setScaleX(1);              page.setScaleY(1);          } else if (position <= 1) { // (0,1]              //页面在由中间页滑动到右侧页面 或者 由右侧页面滑动到中间页              // 淡入淡出效果              page.setAlpha(1 - position);              // 反方向移动              page.setTranslationX(pageWidth * -position);              // 0.75-1比例之间缩放              float scaleFactor = MIN_SCALE                      + (1 - MIN_SCALE) * (1 - Math.abs(position));              page.setScaleX(scaleFactor);              page.setScaleY(scaleFactor);          } else { // (1,+Infinity]              // 页面远离右侧页面              page.setAlpha(0);          }        }  }</code></pre>    <p>实现效果:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e71991fb37668a2c0dd9c3d73d88d90b.gif"></p>    <p> </p>    <p>以上是一些ViewPager做引导页做用的到一些知识点,希望和大家分享共同学习。由于水平有限,有什么不对的地方欢迎指正。</p>    <p> </p>    <p> </p>