环境
- 环境:Android Studio 4.0
- 语言:Java
- 特点:简单,易懂,效果爆炸
分析
ViewPager
是android扩展包v4包中的类,这个类可以让用户左右切换当前的view,它直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的view类,然后再提供一个PagerAdapter适配器类给它提供数据,再实现PageTransformer接口,Google的官方示例, 便可以得到如下效果了
效果.gif
Google的官方示例具体实现,有两种不同得实现效果
- 第一种,深度页面变形,如上图所示效果
import android.util.Log;
import android.view.View;
import androidx.viewpager.widget.ViewPager;
public class DepthPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
@Override
public void transformPage(View view, float position) {
Log.d("DepthPageTransformer", view.getTag() + " , " + position + "");
int pageWidth = view.getWidth();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // (0,1]
// Fade the page out.
view.setAlpha(1 - position);
// Counteract the default slide transition
view.setTranslationX(pageWidth * -position);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
- 第二种,缩小页面变形
import android.annotation.SuppressLint;
import android.util.Log;
import android.view.View;
import androidx.viewpager.widget.ViewPager;
public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
@SuppressLint("NewApi")
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
Log.e("TAG", view + " , " + position + "");
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1)
{ // [-1,1]
// Modify the default slide transition to shrink the page as well
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE)
/ (1 - MIN_SCALE) * (1 - MIN_ALPHA));
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
大家如果想知道具体效果,不如在自己的电脑跑一下,看下到底有哪些变化
不过不管是那种实现,可以看出来,这里当position位于(负无穷,-1)和(1,正无穷)这两个区间的的时候,给page的透明度设为0,在[-1,1]这个区间根据一些相关极限对page进行了一些缩放和平移的操作。然后只需要在使用的时候加上这行代码
mViewPager.setPageTransformer(false, new DepthPageTransformer());
就能实现如上的效果了。关键就是这里计算的这些公式是怎么的出来的呢?这便是我们今天要讨论的重点了。
首先我们看一下这两个参数的解释
public interface PageTransformer {
/**
* Apply a property transformation to the given page.
* 对给定的page施加一个属性切换效果
*
* @param page Apply the transformation to this page
将转换效果引用到此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.
* 相对于当前处于中心显示的page的postion。
* 0是当前页面。1是右侧页面。
* -1是左侧页面。
*/
void transformPage(View page, float position);
}
参考网上大神的测试总结,上面大概的意思就是
- 滑动开始前每个页面的postion是一个整数,当前页面为0,左侧页面position值为0 - 相对于当前页面偏移页面数,右侧页面postion值 0 + 相对于当前页面偏移页面数
- 滑动结束后,每个页面的postion依然是一个整数,数值依然符合上一条规则,不过当前页面已经改变。也可以说左滑全部 -1,右滑全部 +1,postion变为0的页面成为新的当前页面
- 每个页面的postion右滑时都在增大,左滑时都在减小,滑动后结果为滑动前结果 ±1
也就是说,不管如何滑动,当前页面和它相邻的页面的position值总是在[-1,1]之间的,所有当我们对它进行透明度、缩放、平移变化时,也需要参考这个
最后我实现了一个简单的PagerAdapter
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.viewpager.widget.PagerAdapter;
import java.util.ArrayList;
public class ViewPagerAdapter extends PagerAdapter {
private ArrayList<ImageView> mViewList;
public ViewPagerAdapter(ArrayList<ImageView> 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));
}
}
总结:以上效果实现特别简单,但是如果想深入了解,还是需要下大力气,这是我参考的两位博主写的简书,写的特别好,简单易懂,十分感谢他们,附上原文地址
https://www.jianshu.com/p/11a819bc5973
https://www.jianshu.com/p/e5abbda4a71c