目录
1 PageTransformer介绍
2、画廊效果
2.1 普通画廊
2.1.1 布局
2.1.2 定义自己的PageTransformer
2.1.3 使用
2.2 3D画廊
Preference
PageTransformer是ViewPager内部定义的一个接口,用于控制ViewPager中item view的滑动效果。
我们可以通过继承PageTransformer 自行定义页面的滑动效果。
/**
* A PageTransformer is invoked whenever a visible/attached page is scrolled.
* This offers an opportunity for the application to apply a custom transformation
* to the page views using animation properties.
*
* As property animation is only supported as of Android 3.0 and forward,
* setting a PageTransformer on a ViewPager on earlier platform versions will
* be ignored.
*/
public interface PageTransformer {
/**
* Apply a property transformation to the given page.
*
* @param page Apply the transformation to this page
* @param 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.
*/
void transformPage(View page, float position);
}
参数:
右滑时:
当前View ,从0---->1;
前一个View,从-1 --->0,逐渐进入视线。
左滑时:
当前View ,从0---->-1;
后一个View,从1 --->0,逐渐进入视线。
如果定义滑动效果,一般我们关注这三个界面就足够了,也就是关注position [-1,1]这个区间。
效果图:
注意:
子布局设置后,其父布局,包括父布局之上的父布局,同样也要设置,否则不生效。
当然也可以使用padding和clipToPadding实现,不过在transformPage(View page, float position)计算时会存在偏差,因为position位置不再是从我们实际想绘制的区域的位置开始了。page位置是从Viewpage起点开始算起的,起点不同了,则position数据就不一样了,因为相对位置发生改变。
findViewById(R.id.rl_outer).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return viewPager.dispatchTouchEvent(event);
}
});
package com.qian.collectionexamples.viewpager_demos;
import android.support.v4.view.ViewPager;
import android.view.View;
/**
* Created by qhm on 2019/4/30.
* Blog : https://blog.csdn.net/qq_37077360
* 普通画廊效果:缩放(也可以加上透明度)
*
* ps:
* 1、缩放会影响page之间的间距,因为viewpager大小固定,内部控件如果缩小居中显示,间距看起来就大了
* 2、如果viewpager的margin小于这个间距,则显示不出前后page【也就是是说,要合理调整scale缩放比例和margin值(或者说viewpager的绘制区域),以达到预期效果】
* 3、如果是粗略计算缩放比例,也可以根据position>0设置 float scaleX = 1 +/- 0.3f * position;或者 float scaleX = Math.max(minScale,1 - Math.abs(position));
*/
public class CommomGalleryPageTransformer implements ViewPager.PageTransformer {
float minAlpha=0.1f;//最小透明度
float minScale=0.75f;//最小缩放比例
@Override
public void transformPage(View page, float position) {//左1(左边紧靠的第1个view)、右1的变化范围只会在[-1,1]
//滑动开始前,每个页面的postion是一个整数,选中的页面为0,
// 左侧页面position值为0 - 相对于当前页面偏移页面数,
// 右侧页面postion值 0 + 相对于当前页面偏移页面数
/*
设置透明度,只需计算当前页 and 前/后两页,也就是position[-1,1]
-1 -> 0 : 左1变为当前页面
左1的透明度是不是由 minAlpha -> 1
0 -> 1 : 当前页面变为右1
当前页面透明度由 1 -> minAlpha
接下来,等比关系求透明度
position position
-1 ----------------> 0 0 ---------------> 1
x1 x2
minAlpha ----------------> 1 1 ---------------> minAlpha
即:
-1 - position position - 0 0 - position position - 1
--------------- = ---------------- , ---------------- = ----------------
minAlpha - x1 x1 - 1 1 - x2 x2 - minAlpha
解得:
x1 = 1 + position - minAlpha*position, x2 = 1 + minAlpha*position - position
*/
//float alpha = 0;
float scale=minScale;
if (0<= position && position <= 1) {//0 -> 1 当前位置滑到右侧位置
// alpha = 1 + minAlpha*position - position;
scale = 1 + minScale * position - position;
}else if (-1 <= position && position < 0) {// -1 -> 0 左侧滑到当前位置
//alpha = 1 + position - minAlpha*position;
scale = 1 + position - minScale * position;
}
//page.setAlpha(alpha);//透明度
page.setScaleX(scale);//尺寸
page.setScaleY(scale);
}
}
ps:上述代码中,透明度代码,根据需要选择是否取消注释。
等比方法比较精确,当然网上也有其他方法:
if(position>0){
scale = 1 - 0.3f * position;//position :0--->1,对应scale: 1-->0.7
}else{
scale = 1 + 0.3f * position;//position :-1--->0,对应scale: 0.7-->1
}
//等价于 scale = 1 - 0.3f * Math.abs(position);
//对比上面的等比方法:position>0时 ,scale = 1 + minScale * position - position = 1+(minScale-1) * position
// position<0时 ,scale = 1 + position - minScale * position = 1+(1-minScale) * position
//
// 有没有发现(minScale-1)就等于-0.3f. 我们要计算的也就是position[-1,1]区域,所以只要将0.3也就是 (1-minScale)换成合适的数值即可。
// 也就是说我们可以直接用该方法取代上面的等比方法,只不过等比方法更严谨一点
或者
scale = Math.max(minScale,1 - Math.abs(position))
adapter = new MyPagerAdapter(getApplicationContext(),dataList);
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(dataList.size());//***不设置,则只会显示一个,可以2,也可以是list 的size
// viewPager.setPageMargin(getResources().getDimensionPixelOffset(R.dimen._10dp));//间距。因为Transformer中有缩放效果(产生额外间距),这里不需要
viewPager.setPageTransformer(true, new CommomGalleryPageTransformer());//普通画廊效果
viewPager.setCurrentItem(1);
//***避免ViewPager两端不能滑动(设置了margin)
findViewById(R.id.rl_outer).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return viewPager.dispatchTouchEvent(event);
}
});
重点:
package com.qian.collectionexamples.viewpager_demos;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.View;
/**
* Created by qhm on 2019/4/30.
* Blog : https://blog.csdn.net/qq_37077360
* 2D画廊效果:缩放+旋转(y轴)
*
* ps:
* 1、缩放会影响page之间的间距,因为viewpager大小固定,内部控件如果缩小居中显示,间距看起来就大了
* 2、如果viewpager的margin小于这个间距,则显示不出前后page【也就是是说,要合理调整minScale和margin值(或者说viewpager的绘制区域),以达到预期效果】
* 3、如果是粗略计算缩放比例,也可以根据position>0设置 float scaleX = 1 +/- 0.3f * position;
*/
public class _3DGalleryPageTransformer implements ViewPager.PageTransformer {
float minScale=0.9f;//最小缩放比例
@Override
public void transformPage(View page, float position) {//左1(左边紧靠的第1个view)、右1的变化范围只会在[-1,1]
//滑动开始前,每个页面的postion是一个整数,选中的页面为0,
// 左侧页面position值为0 - 相对于当前页面偏移页面数,
// 右侧页面postion值 0 + 相对于当前页面偏移页面数
float scale=minScale;
if (0<= position && position <= 1) {//0 -> 1 当前位置滑到右侧位置
scale = 1 + minScale * position - position;
}else if (-1 <= position && position < 0) {// -1 -> 0 左侧滑到当前位置
scale = 1 + position - minScale * position;
}
page.setScaleX(scale);//尺寸
page.setScaleY(scale);
//旋转角度
float rotate = 30 * Math.abs(position);
Log.d("ceshi","position=="+position);
// if (0<= position && position < 1) {//0 -> 1 当前位置滑到右侧位置.不能包含0,1
// rotate = - 15 * Math.abs(position);
// }else if (-1 <= position && position < 0) {// -1 -> 0 左侧滑到当前位置 不能包含1
// rotate = 15 * Math.abs(position);
// }
// page.setRotationY(rotate);
if (position < 0){
page.setRotationY(rotate);
} else if (position >=0 ){//position从0变化到1,page逐渐向右滑动
page.setRotationY(-rotate);
}
}
}
注意:这里 if (position < 0)判断,是因为会预先显示前一页/后一页的一部分,如果限定[-1,0]、[0,-1]则滑动时会有一个交叉到旋转的跳转,不美观。
PageTransformer实现一个层叠的卡片
利用ViewPager实现3D画廊效果及其图片加载优化 ☆☆☆☆☆ 涉及图片缓存Lru+异步加载 。如果需要展示大量图片,则需要考虑优化
Android ViewPager切换之PageTransformer接口中transformPage方法解析
ViewPager PageTransformer探索 ☆☆☆☆☆