当前位置:  数据库>oracle

Android 自定义 ViewPager 打造千变万化的图片切换效果

    来源: 互联网  发布时间:2017-06-19

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

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

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

Android 自定义 ViewPager 打造千变万化的图片切换效果[图片]

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

本文相关源码下载地址:

------------------------------------------分割线------------------------------------------

免费下载地址在 http://linux.linuxidc.com/

用户名与密码都是www.linuxidc.com

具体下载目录在 /2015年资料/8月/8日/Android 自定义 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

,然后滑动的时候,通过get(position)取出,比如上述效果,始终是右边的View变化,要么从小到大,要么从大到小

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

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

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

3、代码

MainActivity

package com.example.zhy_jazzyviewpager;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;

public class MainActivity extends Activity
{
 protected static final String TAG = "MainActivity";
 private int[] mImgIds;
 private MyJazzyViewPager mViewPager;

 @Override
 protected void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mImgIds = new int[] { R.drawable.a, R.drawable.b, R.drawable.c,
    R.drawable.d };
  mViewPager = (MyJazzyViewPager) findViewById(R.id.id_viewPager);
  mViewPager.setAdapter(new PagerAdapter()
  {

   @Override
   public boolean isViewFromObject(View arg0, Object arg1)
   {
    return arg0 == arg1;
   }

   @Override
   public void destroyItem(ViewGroup container, int position,
     Object object)
   {
    container.removeView((View) object);
   }

   @Override
   public Object instantiateItem(ViewGroup container, int position)
   {
    ImageView imageView = new ImageView(MainActivity.this);
    imageView.setImageResource(mImgIds[position]);
    imageView.setScaleType(ScaleType.CENTER_CROP);
    container.addView(imageView);
    mViewPager.setObjectForPosition(imageView, position);
    return imageView;
   }

   @Override
   public int getCount()
   {
    return mImgIds.length;
   }
  });

 }

}

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

主要看自定义的ViewPager

package com.example.zhy_jazzyviewpager;

import java.util.HashMap;
import java.util.LinkedHashMap;

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.nineoldandroids.view.ViewHelper;

public class MyJazzyViewPager extends ViewPager
{
 private float mTrans;
 private float mScale;
 /**
  * 最大的缩小比例
  */
 private static final float SCALE_MAX = 0.5f;
 private static final String TAG = "MyJazzyViewPager";
 /**
  * 保存position与对于的View
  */
 private HashMap mChildrenViews = new LinkedHashMap();
 /**
  * 滑动时左边的元素
  */
 private View mLeft;
 /**
  * 滑动时右边的元素
  */
 private View mRight;

 public MyJazzyViewPager(Context context, AttributeSet attrs)
 {
  super(context, attrs);
 }

 @Override
 public void onPageScrolled(int position, float positionOffset,
   int positionOffsetPixels)
 {

//  Log.e(TAG, "position=" + position+", positionOffset = "+positionOffset+" ,positionOffsetPixels =  " + positionOffsetPixels+" , currentPos = " + getCurrentItem());
 
  //滑动特别小的距离时,我们认为没有动,可有可无的判断
  float effectOffset = isSmall(positionOffset) ? 0 : positionOffset;
 
  //获取左边的View
  mLeft = findViewFromObject(position);
  //获取右边的View
  mRight = findViewFromObject(position + 1);
 
  // 添加切换动画效果
  animateStack(mLeft, mRight, effectOffset, positionOffsetPixels);
  super.onPageScrolled(position, positionOffset, positionOffsetPixels);
 }

 public void setObjectForPosition(View view, int position)
 {
  mChildrenViews.put(position, view);
 }

 /**
  * 通过过位置获得对应的View
  *
  * @param position
  * @return
  */
 public View findViewFromObject(int position)
 {
  return mChildrenViews.get(position);
 }

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

 protected void animateStack(View left, View right, float effectOffset,
   int positionOffsetPixels)
 {
  if (right != null)
  {
   /**
    * 缩小比例 如果手指从右到左的滑动(切换到后一个):0.0~1.0,即从一半到最大
    * 如果手指从左到右的滑动(切换到前一个):1.0~0,即从最大到一半
    */
   mScale = (1 - SCALE_MAX) * effectOffset + SCALE_MAX;
   /**
    * x偏移量: 如果手指从右到左的滑动(切换到后一个):0-720 如果手指从左到右的滑动(切换到前一个):720-0
    */
   mTrans = -getWidth() - getPageMargin() + positionOffsetPixels;
   ViewHelper.setScaleX(right, mScale);
   ViewHelper.setScaleY(right, mScale);
   ViewHelper.setTranslationX(right, mTrans);
  }
  if (left != null)
  {
   left.bringToFront();
  }
 }
}

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

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

我们的布局文件:

   

更多详情见请继续阅读下一页的精彩内容:


    
 
 

您可能感兴趣的文章:

  • android-viewpager-indicator
  • android教程viewpager自动循环和手动循环
  • Android ViewPager相册横向移动的实现方法
  • Android利用ViewPager实现滑动广告板实例源码
  • android配合viewpager实现可滑动的标签栏示例分享
  • 使用ViewPager实现android软件使用向导功能实现步骤
  • android开启免提切换功能示例
  • Android Activity切换(跳转)时出现黑屏的解决方法 分享
  • 解析Android横竖屏切换的问题
  • android fm单体声和立体声的切换示例代码
  • android横竖屏切换不重启activity解决方案
  • Android实现Activity界面切换添加动画特效的方法
  • android横竖屏切换时候Activity的生命周期
  • android播放视频时在立体声与单声道之间切换无变化原因分析及解决
  • 认认真真发一次,framebuffer 切换问题!!Android平台
  • Android实现动态切换组件背景的方法
  • android实现在横竖屏切换时页面信息不被重置的示例分享
  • Android基础之使用Fragment控制切换多个页面
  • Android TabWidget切换卡的实现应用
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • android 自定义Android菜单背景的代码
  • android自定义控件和自定义回调函数步骤示例
  • Android 去掉自定义dialog的白色边框的简单方法
  • Android实现动态切换组件背景的方法 iis7站长之家
  • android intent使用定义标题
  • Android开发笔记之:如何安全中止一个自定义线程Thread的方法
  • Android自定义View设定到FrameLayout布局中实现多组件显示的方法 分享
  • Android 自定义View的使用介绍
  • Android自定义Style实现方法
  • Android中自定义标题栏样式的两种方法
  • Android中自定义加载样式图片的具体实现
  • android自定义toast(widget开发)示例
  • Android中的Button自定义点击效果实例代码
  • android自定义按钮示例(重写imagebutton控件实现图片按钮)
  • Android自定义shape的使用示例
  • android之自定义Toast使用方法
  • Android自定义桌面功能代码实现
  • Android布局——Preference自定义layout的方法
  • Android自定义格式显示Button的布局思路
  • 解析Android中使用自定义字体的实现方法
  • 申请Android Map 的API Key(v2)的最新申请方式(SHA1密钥)
  • Android瀑布流实例 android_waterfall
  • Android开发需要的几点注意事项总结
  • Android系统自带样式 (android:theme)
  • android 4.0 托管进程介绍及优先级和回收机制
  • Android网络共享软件 Android Wifi Tether
  • Android访问与手机通讯相关类的介绍
  • Android 图标库 Android GraphView
  • Android及andriod无线网络Wifi开发的几点注意事项
  • 轻量级Android开发工具 Android Tools
  • Android 2.3 下StrictMode介绍


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3