zoukankan      html  css  js  c++  java
  • 【转】android 自定义ViewPager,修改原动画

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38026503 

    记 得第一次见到ViewPager这个控件,瞬间爱不释手,做东西的主界面通通ViewPager,以及图片切换也抛弃了ImageSwitch之类的,开 始让ViewPager来做。时间长了,ViewPager的切换效果觉得枯燥,形成了审美疲劳~~我们需要改变,今天教大家如何改变ViewPager 切换时的效果,实现个性化的图片切换~~

    看一下这样效果的图片切换:

    是不是比传统的效果个性很多,嘿嘿~~其实很简单,学习完这篇博客,保证你可以自定义切换效果,做出各种丧心病狂的切换~~

    1、制作前的分析

    观察下效果图,实际上改变的就是切换时的动画,那么简单了,只需要用户在切换时,拿到当前的View和下一个View,然后添加动画是不是就可以了。好,第一步,获取用户切换时的当前View和切换至的目的View。

    我们在来看一下,如果或者了当前View和目的View,对于动画我们需要缓慢的变化,最好是根据用户的手势滑动。比如上述效果,用户滑动时,目的图片根据用户滑动距离缓缓出现和慢慢变大。好,第二步,设计动画的梯度变化。

    经过分析,我们总结出两个步骤,下面我们开始一步一步来打造~~~

    2、获取用户切换时当前View和切换至的目的View。

    ViewPager 也需要监听用户的手势,所以肯定提供了某个方法。于是纵观ViewPager的方法,发现了一个叫做 onPageScrolled(int position, float positionOffset, int positionOffsetPixels)的方法~~

    没错就是这个方法:在页面滚动时调用~

    下面仔细研究下这几个参数:

    直接说测试结果:

    在非第一页与最后一页时,滑动到下一页,position为当前页位置;滑动到上一页:position为当前页-1

    positionOffset 滑动到下一页,[0,1)区间上变化;滑动到上一页:(1,0]区间上变化

    positionOffsetPixels这个和positionOffset很像:滑动到下一页,[0,宽度)区间上变化;滑动到上一页:(宽度,0]区间上变化

    第一页时:滑动到上一页position=0 ,其他基本为0 ;最后一页滑动到下一页 position为当前页位置,其他两个参数为0

    豁然发现,我们需要的步骤的第二步解决了,positionOffset很适合作为,渐变,缩放的控制参数;positionOffsetPixels则可以作为平移等的控制参数。

    那么如何获得当前View和目的View呢:

    分享几个我的歧途:

    1、【错误】我 通过getChildAt(position),getChildAt(position+1),getChildAt(position-1)获得滑动 时,左右的两个View;乍一看,还真觉得不错~~~在代码写出来,再乍效果也出不来~~错误原因:我们忽略一个特别大的东西,ViewPager的机 制,滑动时动态加载和删除View,ViewPager其实只会维持2到3个View,而position的范围基本属于无限~~

    2、【错误】我 通过getCurrentItem获得当前的位置,然后+1,-1获得后一个或者前一个~~正在窃喜,赶快代码改过来,效果怎么也不对,乱七八糟的~~仔 细观察日志,这个getCurrentItem当用户手指离开的屏幕,Page还在动画执行时,就改变了~~难怪~整个滑动过程并不是固定的~~唉,心都 碎了~

    3、【错误】position在整个滑动的过程中是不变 化的,而且ViewPager会保存2个或3个View;那么我考虑,如果是第一页、或者最后一页那么我取getChildAt(0)和 getChildAt(1),如果在其他页面则为getChildAt(0),getChildAt(2),然后经过一系列的变化~我想这会总该对了吧, 于是我遇到第一问题,第一页的时候,不管左右position都为0,尼玛,这哪个为左View,哪个为右View~~

    说了这么多错误,大家可以绕过这些弯路,也能从这些弯路里面看出点什么~

    下 面说正确的,其实ViewPager在添加一个View或者销毁一个View时,是我们自己的PageAdapter中控制的,于是我们可以在 ViewPager里面维系一个HashMap<Position,View>,然后滑动的时候,通过get(position)取出,比如 上述效果,始终是右边的View变化,要么从小到大,要么从大到小

    那么滑倒下一页:左边的View:map.get(position) ,右边的View : map.get(position+1) . 

    那么滑倒上一页:左边的View : map.get(position) , 右边的View : map.get(position+1) , 一样的,因为滑到上一页,position为当前页-1

    好了,至此,我们分析了且解决了所有步骤。

     1 package com.example.zhy_jazzyviewpager;
     2 
     3 import android.app.Activity;
     4 import android.os.Bundle;
     5 import android.support.v4.view.PagerAdapter;
     6 import android.view.Menu;
     7 import android.view.View;
     8 import android.view.ViewGroup;
     9 import android.widget.ImageView;
    10 import android.widget.ImageView.ScaleType;
    11 
    12 public class MainActivity extends Activity
    13 {
    14 protected static final String TAG = "MainActivity";
    15 private int[] mImgIds;
    16 private MyJazzyViewPager mViewPager;
    17 
    18 @Override
    19 protected void onCreate(Bundle savedInstanceState)
    20 {
    21 super.onCreate(savedInstanceState);
    22 setContentView(R.layout.activity_main);
    23 mImgIds = new int[] { R.drawable.a, R.drawable.b, R.drawable.c,
    24 R.drawable.d };
    25 mViewPager = (MyJazzyViewPager) findViewById(R.id.id_viewPager);
    26 mViewPager.setAdapter(new PagerAdapter()
    27 {
    28 
    29 @Override
    30 public boolean isViewFromObject(View arg0, Object arg1)
    31 {
    32 return arg0 == arg1;
    33 }
    34 
    35 @Override
    36 public void destroyItem(ViewGroup container, int position,
    37 Object object)
    38 {
    39 container.removeView((View) object);
    40 }
    41 
    42 @Override
    43 public Object instantiateItem(ViewGroup container, int position)
    44 {
    45 ImageView imageView = new ImageView(MainActivity.this);
    46 imageView.setImageResource(mImgIds[position]);
    47 imageView.setScaleType(ScaleType.CENTER_CROP);
    48 container.addView(imageView);
    49 mViewPager.setObjectForPosition(imageView, position);
    50 return imageView;
    51 }
    52 
    53 @Override
    54 public int getCount()
    55 {
    56 return mImgIds.length;
    57 }
    58 });
    59 
    60 }
    61 
    62 }

    这个很常见的代码,就是初始化ViewPager~~就没啥可说的了~~有一点需要注意:在instantiateItem方法,我们多调用了一个 mViewPager.setObjectForPosition(imageView, position);其实就是为了给我们的Map存值

    主要看自定义的ViewPager

      1 package com.example.zhy_jazzyviewpager;
      2 
      3 import java.util.HashMap;
      4 import java.util.LinkedHashMap;
      5 
      6 import android.content.Context;
      7 import android.support.v4.view.ViewPager;
      8 import android.util.AttributeSet;
      9 import android.util.Log;
     10 import android.view.View;
     11 
     12 import com.nineoldandroids.view.ViewHelper;
     13 
     14 public class MyJazzyViewPager extends ViewPager
     15 {
     16 private float mTrans;
     17 private float mScale;
     18 /**
     19 * 最大的缩小比例
     20 */
     21 private static final float SCALE_MAX = 0.5f;
     22 private static final String TAG = "MyJazzyViewPager";
     23 /**
     24 * 保存position与对于的View
     25 */
     26 private HashMap<Integer, View> mChildrenViews = new LinkedHashMap<Integer, View>();
     27 /**
     28 * 滑动时左边的元素
     29 */
     30 private View mLeft;
     31 /**
     32 * 滑动时右边的元素
     33 */
     34 private View mRight;
     35 
     36 public MyJazzyViewPager(Context context, AttributeSet attrs)
     37 {
     38 super(context, attrs);
     39 }
     40 
     41 @Override
     42 public void onPageScrolled(int position, float positionOffset,
     43 int positionOffsetPixels)
     44 {
     45 
     46 // Log.e(TAG, "position=" + position+", positionOffset = "+positionOffset+" ,positionOffsetPixels = " + positionOffsetPixels+" , currentPos = " + getCurrentItem());
     47 //滑动特别小的距离时,我们认为没有动,可有可无的判断
     48 float effectOffset = isSmall(positionOffset) ? 0 : positionOffset;
     49 //获取左边的View
     50 mLeft = findViewFromObject(position);
     51 //获取右边的View
     52 mRight = findViewFromObject(position + 1);
     53 // 添加切换动画效果
     54 animateStack(mLeft, mRight, effectOffset, positionOffsetPixels);
     55 super.onPageScrolled(position, positionOffset, positionOffsetPixels);
     56 }
     57 
     58 public void setObjectForPosition(View view, int position)
     59 {
     60 mChildrenViews.put(position, view);
     61 }
     62 
     63 /**
     64 * 通过过位置获得对应的View
     65 *
     66 * @param position
     67 * @return
     68 */
     69 public View findViewFromObject(int position)
     70 {
     71 return mChildrenViews.get(position);
     72 }
     73 
     74 private boolean isSmall(float positionOffset)
     75 {
     76 return Math.abs(positionOffset) < 0.0001;
     77 }
     78 
     79 protected void animateStack(View left, View right, float effectOffset,
     80 int positionOffsetPixels)
     81 {
     82 if (right != null)
     83 {
     84 /**
     85 * 缩小比例 如果手指从右到左的滑动(切换到后一个):0.0~1.0,即从一半到最大
     86 * 如果手指从左到右的滑动(切换到前一个):1.0~0,即从最大到一半
     87 */
     88 mScale = (1 - SCALE_MAX) * effectOffset + SCALE_MAX;
     89 /**
     90 * x偏移量: 如果手指从右到左的滑动(切换到后一个):0-720 如果手指从左到右的滑动(切换到前一个):720-0
     91 */
     92 mTrans = -getWidth() - getPageMargin() + positionOffsetPixels;
     93 ViewHelper.setScaleX(right, mScale);
     94 ViewHelper.setScaleY(right, mScale);
     95 ViewHelper.setTranslationX(right, mTrans);
     96 }
     97 if (left != null)
     98 {
     99 left.bringToFront();
    100 }
    101 }
    102 }

    可以看到,核心代码都是onPageScrolled,我们通过 findViewFromObject(position); findViewFromObject(position + 1);分别获取了左右两边的View,然后添加动画效果;当前这个例子添加了两个动画,一个是从0.5放大到1.0或者1.0缩小到0.5,没错由我们的 positionOffset提供梯度的变化~~还有个平移的动画:下一页直接移动到当前屏幕(默认是在右边,可以注释这个效果,怎么运行看看),然后不 断的通过positionOffsetPixels抵消原来默认移动时的位移,让用户感觉它就在原地放大缩小~~

    好了,这样就实现了~~你可以随便写自己喜欢的动画效果,比如在默认上面加个淡入淡出或者神马,随便~~是不是很随意~~

    我们的布局文件:

     1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2 xmlns:tools="http://schemas.android.com/tools"
     3 android:layout_width="match_parent"
     4 android:layout_height="match_parent"
     5 >
     6 
     7 <com.example.zhy_jazzyviewpager.MyJazzyViewPager
     8 android:layout_width="wrap_content"
     9 android:layout_height="wrap_content"
    10 android:id="@+id/id_viewPager" />
    11 
    12 </RelativeLayout>
    4、JazzyViewPager的使用

    其实上面的实现就是github上JazzyViewPager的源码,用法不用说了,就是我们的MainActivity,它内置了大概10来种效果,我们可以通过代码或者布局上面设置动画效果~~我们上面的例子效果,它叫做Stack;

    使用JazzViewPager的代码:其实基本一样~~最后也会贴上JazzyViewPager的源码的下载

    MainActivity

     1 package com.jfeinstein.jazzyviewpager;
     2 
     3 import com.jfeinstein.jazzyviewpager.JazzyViewPager.TransitionEffect;
     4 
     5 import android.app.Activity;
     6 import android.os.Bundle;
     7 import android.support.v4.view.PagerAdapter;
     8 import android.view.View;
     9 import android.view.ViewGroup;
    10 import android.widget.ImageView;
    11 import android.widget.ImageView.ScaleType;
    12 
    13 public class MainActivity extends Activity
    14 {
    15 protected static final String TAG = "MainActivity";
    16 private int[] mImgIds;
    17 private JazzyViewPager mViewPager;
    18 
    19 @Override
    20 protected void onCreate(Bundle savedInstanceState)
    21 {
    22 super.onCreate(savedInstanceState);
    23 setContentView(R.layout.activity_main);
    24 mImgIds = new int[] { R.drawable.a, R.drawable.b, R.drawable.c,
    25 R.drawable.d };
    26 mViewPager = (JazzyViewPager) findViewById(R.id.id_viewPager);
    27 //设置切换效果
    28 mViewPager.setTransitionEffect(TransitionEffect.Stack);
    29 mViewPager.setAdapter(new PagerAdapter()
    30 {
    31 
    32 @Override
    33 public boolean isViewFromObject(View arg0, Object arg1)
    34 {
    35 return arg0 == arg1;
    36 }
    37 
    38 @Override
    39 public void destroyItem(ViewGroup container, int position,
    40 Object object)
    41 {
    42 container.removeView((View) object);
    43 }
    44 
    45 @Override
    46 public Object instantiateItem(ViewGroup container, int position)
    47 {
    48 ImageView imageView = new ImageView(MainActivity.this);
    49 imageView.setImageResource(mImgIds[position]);
    50 imageView.setScaleType(ScaleType.CENTER_CROP);
    51 container.addView(imageView);
    52 mViewPager.setObjectForPosition(imageView, position);
    53 return imageView;
    54 }
    55 
    56 @Override
    57 public int getCount()
    58 {
    59 return mImgIds.length;
    60 }
    61 });
    62 
    63 }
    64 
    65 }

    与我们的代码唯一区别就是:

    //设置切换效果
    mViewPager.setTransitionEffect(TransitionEffect.Stack);

    它有12中可选的切换效果,其实就是写了12个切换的动画~~~

    源码下载地址

     自己网盘下载地址:地址

  • 相关阅读:
    推荐一款适合Dynamics 365/Dynamics CRM 2016 使用的弹出窗插件AlertJs
    SSRS 报表开发过程中,除数为0的处理
    [Dynamics 365] 关于Currency的一点随笔
    [Microsoft Dynamics CRM 2016]Invalid Action – The selected action was not valid 错误的诱因及解决方法
    [Dynamics CRM 2016]如何配置多语言显示
    获取经过跳转后的url地址
    Microsoft Dynamics CRM 2013 --针对特定实体,取消保存功能(包含自动保存)
    Microsoft Dynamics CRM 2013 --选项集的多选
    我自己也是找了好久这样的远程打印软件
    QTextStream 读取文件乱码的解决办法
  • 原文地址:https://www.cnblogs.com/liangstudyhome/p/3879568.html
Copyright © 2011-2022 走看看