Android 左右切换页面item

转载请标明出处: 【明明爱的博客】

一、概述

好的交互会让人用起来很舒服,其实很多页面是没有必要切换页面的,例如图上密码登录和短信登录的两种情况。什么都不说,先上图:

这里写图片描述
这种登录方式没必要让用户要切换界面。

二、分析

其实以上的实现方式有很多,如viewpager、自定义view等。
本文先用viewpager来实现,后续会出用自定义view的文章。

难点分析:
- 怎样得到滑动时的事件
- 通过什么数值来得到动画的比例
- 得到需要滑动的view

ok,其实同过分析就这两个难点而已。通过查看viewpager的api可以知道viewpager提供了onPageScrolled(int position, float offset, int offsetPixels)方法,刚好解决了得到滑动事件的难点。

  • position 当前viewpager的fragment 第一个为0,第二个为1,如此类推
  • offset 滑动比例 如果position 从 0到1时 滑动比例:0~1, 当position = 1时,offset=0, offsetPixels=0。 如果position 从1~0时 滑动比例:1~0。
  • offsetPixels 屏幕宽度
package com.mingmingai.test_custom_login.customview;

/**
 * Created by 明明爱 
 */
public class CustomViewpager extends ViewPager {

     private View leftView;
     private View rightView;
     private List<Fragment> fragmentsList;
     private float mTrans;   //滑动的距离
     private float mLScaleY;   //最大的缩小比例
     private static final float lDefaultScaleX = 0.9f;   //leftView默认缩小X的比例
     private static final float defaultScaleY = 0.9f;   //默认缩小Y的比例
     private static final float scalePrecent = 0.1f;   //默认缩小的比例
     private int screenWidth = 0;   //屏幕宽度
     private int scrollX = 230;   //滑动多少距离之后向相反方向返回
     private int defaultTranslationX = 10;   //默认移动的X距离

     public CustomViewpager(Context context) {
          super(context);
     }

     public CustomViewpager(Context context, AttributeSet attrs) {
          super(context, attrs);
          screenWidth = CommonUtils.getWindowWidth(context);
     }

     public void setFragmentsList(List<Fragment> fragmentsList) {
          this.fragmentsList = fragmentsList;
     }

     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
          return false;   //拦截
     }

     @Override
     public boolean onTouchEvent(MotionEvent ev) {
          return false;   //不给viewpager滑动
     }

     @Override
     protected void onPageScrolled(int position, float offset, int offsetPixels) {
          if (position +1<= fragmentsList.size() - 1) {
               // 滑动特别小的距离时,我们认为没有动,可有可无的判断
               float effectOffset = isSmall(offset) ? 0 : offset;
               leftView = fragmentsList.get(position).getView();   //得到View

               rightView = fragmentsList.get(position + 1).getView();   //得到View
               startAnimate(leftView, rightView, effectOffset, offsetPixels);
          }
          super.onPageScrolled(position, offset, offsetPixels);
     }

     private void startAnimate(View leftView, View rightView, float effectOffset, int positionOffsetPixels) {
          if (leftView != null)
          {
               manageLayer(leftView, true);
               mLScaleY = (float) (defaultScaleY - scalePrecent*effectOffset);

               if (positionOffsetPixels > scrollX){
                    mTrans = scrollX*((positionOffsetPixels-scrollX)/(screenWidth - scrollX))+(positionOffsetPixels-scrollX)-defaultTranslationX;
                    rightView.bringToFront();
               }else{
                    leftView.bringToFront();
                    mTrans = -defaultTranslationX;
               }
               ViewHelper.setTranslationX(leftView,mTrans);
               ViewHelper.setScaleX(leftView, lDefaultScaleX);
               ViewHelper.setScaleY(leftView, mLScaleY);
          }
          if (rightView != null)
          {
               manageLayer(rightView, true);
               mLScaleY = (float) (defaultScaleY - scalePrecent*(1-effectOffset));
               ViewHelper.setScaleX(rightView, lDefaultScaleX);
               ViewHelper.setScaleY(rightView, mLScaleY);

               if (positionOffsetPixels > scrollX){
                    mTrans = -getWidth()+scrollX*2+defaultTranslationX;
                    if (Math.abs(mTrans) >= getWidth()-positionOffsetPixels){
                         mTrans = -getWidth() - getPageMargin() + positionOffsetPixels+defaultTranslationX;
                    }
               }else{
                    mTrans = -getWidth() - getPageMargin() + positionOffsetPixels*2+defaultTranslationX;
               }
               ViewHelper.setTranslationX(rightView, mTrans);
          }
     }

     @TargetApi(Build.VERSION_CODES.HONEYCOMB)
     private void manageLayer(View v, boolean enableHardware)
     {
//      if (!API_11)
//          return;
          int layerType = enableHardware ? View.LAYER_TYPE_HARDWARE
               : View.LAYER_TYPE_NONE;
          if (layerType != v.getLayerType())
               v.setLayerType(layerType, null);
     }

     private boolean isSmall(float positionOffset)
     {
          return Math.abs(positionOffset) < 0.0001;
     }
}

代码分析:
leftView和rightView分别是要滑动的两个View,主要的动画都在startAnimate()里,mLScaleY是leftView缩小或放大的比例。if (positionOffsetPixels > scrollX) 当leftView滑动多少距离之后向相反方向返回,之后将rightView在前面显示:rightView.bringToFront();。mTrans是算出需要滑动的距离。
其实viewpager默认的布局是:
这里写图片描述
所以一开始就把fragment2移动到了fragment1的下面:mTrans = -getWidth() - getPageMargin() + positionOffsetPixels*2+defaultTranslationX;
要理解了动画滑动是滑动view的内容,而非view的实体。但viewpager本身的滑动是会滑动实体的,通过看viewpager的源码,发现viewpager的动画是用了Scroller对象来滑动的。Scroller每次滑动都会调用onDraw里的computeScroll()方法。只有理解好这含义,其他就很好理解了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值