效果图
实现方式核心思想是自定义PageTransformer继承ViewPager.PageTransformer,精确控制每一个page的动效。
PageTransformer的transformPage方法并不会区分当前的page是哪一个,所以需要我们自己去识别,我的方法是每个page添加一个text显示position,在PageTransformer中获取Text显示的内容来区分,实际使用的时候将textVew隐藏就行了
package com.example.anchorviewpagedemo;import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.widget.TextView;import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager2.widget.ViewPager2;/*
居中效果*/
public class OverlayTransformerLan5 implements ViewPager.PageTransformer {// public static final String TAG = OverlayTransformerLan2.class.getSimpleName();public static final String TAG = "YinTest_";public float mOffset = 40 * 2 - 20;public int viewPageMarginHorizontal = 30;public float screenWidth;private Context mContext;private float mMinScale;public ViewPager mViewPager;private int saveIndex = -1;private int leftMostPageIndex = -1;private int leftPageIndex = -1;private int currentPageIndex = -1;private int rightPageIndex = -1;private int rightMostPageIndex = -1;private int dataSize = -1;public OverlayTransformerLan5(float minScale) {mMinScale = minScale;}public OverlayTransformerLan5(Context context, ViewPager viewPager, int size, float minScale) {mMinScale = minScale;mContext = context;mViewPager = viewPager;dataSize = size;//适配viewPage的边距,左右各10dpviewPageMarginHorizontal = Utils.dp2Px(mContext, viewPageMarginHorizontal);screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;}@Overridepublic void transformPage(@NonNull View view, float position) {
// view.setAlpha(0.5f);int pageWidth = view.getWidth();int pageHeight = view.getHeight();int cardViewWidth = view.findViewById(R.id.card_view).getWidth();final float cardMargin = (pageWidth - cardViewWidth) / 2f;TextView mTvPosition = view.findViewById(R.id.tv_position);int viewIndex = Integer.parseInt(mTvPosition.getText().toString());view.setPivotY(pageHeight / 2f);view.setPivotX(pageWidth / 2f);// Log.i("YinTest_", "transformPage position=" + position + ",pageWidth = " + pageWidth + ",viewIndex = "+viewIndex);if (viewIndex == leftMostPageIndex) {transformMostLeftPage(view, position, cardMargin, cardViewWidth, pageWidth);} else if (viewIndex == leftPageIndex) {transformLeftPage(view, position, cardMargin, cardViewWidth, pageWidth);} else if (viewIndex == currentPageIndex) {transformCenterPage(view, position, cardMargin, cardViewWidth, pageWidth);} else if (viewIndex == rightPageIndex) {transformRightPage(view, position, cardMargin, cardViewWidth, pageWidth);} else if (viewIndex == rightMostPageIndex) {transformMostRightPage(view, position, cardMargin, cardViewWidth, pageWidth);}}public boolean isOutLimit(float initPosition, float position) {if (position > initPosition + 1 || position < initPosition - 1) {return true;}return false;}private void transformMostLeftPage(View view, float position, float cardMargin, int cardViewWidth, int pageWidth) {if (isOutLimit(-2, position)) {return;}float scaleFactor = (1 + position) * (1 - mMinScale) + mMinScale;//view.setScaleX(scaleFactor);view.setScaleY(scaleFactor);float anchorLeft = cardMargin + cardViewWidth;//左页左边的锚点float startPosition = pageWidth * 2;view.setTranslationZ(position);view.setPivotX(0);//初始状态position=-2.0if (position == -2) {view.setTranslationX(startPosition);}//向右滑动if (position > -2 && position < -1) {//startPosition~anchorLeft 逆滑动float translationX = (-position - 1) * startPosition + (position + 2) * anchorLeft;view.setTranslationX(translationX);}//向左滑动if (position < -2 && position > -3) {//startPosition~anchorLeft 保持其实际位置不变,不影响其他页面翻转
// Log.i("YinTest_", " 最左页 向左滑动 position=" + position + ",translationX = " + (-position - 1));view.setTranslationX(startPosition + (-(position + 2)) * pageWidth);}//变为右页(相对于起始位置)if (position == -1) {view.setTranslationX(anchorLeft);}//变为左页(相对于起始位置)if (position == -3) {//向左滑动保持不变,但变为左页后跳转到正常显示位置view.setTranslationX(0);}}private void transformLeftPage(View view, float position, float cardMargin, int cardViewWidth, int pageWidth) {if (isOutLimit(-1, position)) {return;}
// Log.i("YinTest_", " position=" + position + ",cardMargin = " + cardMargin);//初始状态position=-1.0,viewIndex = 0float scaleFactor = (1 + position) * (1 - mMinScale) + mMinScale;//view.setScaleX(scaleFactor);view.setScaleY(scaleFactor);float anchorLeft = cardMargin + cardViewWidth;//左页左边的锚点view.setTranslationZ(position);view.setPivotX(0);
// view.setAlpha(0.5f);if (position == -1) {//初始状态 position == -1view.setTranslationX(anchorLeft);}if (position < -1 && position > -2) {//向左滑动 anchorLeft ~ pageWidth*2view.setTranslationX((position+2)*anchorLeft + (-2*position-2) * pageWidth);}//向右滑动if (position > -1 && position < 0) {//anchorLeft ~ 0view.setTranslationX((-position) * anchorLeft);}//变为左页(相对于起始位置)if (position == -2) {view.setTranslationX(pageWidth*2);}//变为右叶(相对于起始位置)if (position == 0) {//左页变为当前页 position =0.0view.setTranslationX(0);}}private void transformCenterPage(View view, float position, float cardMargin, int cardViewWidth, int pageWidth) {if (isOutLimit(0, position)) {return;}float anchorLeft = cardMargin + cardViewWidth;//初始状态 position=0.0,viewIndex = 1//向左滑动if (position > -1 && position < 0) {//0 ~ anchorLeftview.setTranslationX(-position * anchorLeft);float scaleFactor = (1 + position) * (1 - mMinScale) + mMinScale;
// view.setScaleX(scaleFactor);view.setScaleY(scaleFactor);view.setPivotX(0);view.setTranslationZ(position);}//变为左页(相对于起始位置)if (position == -1) {view.setTranslationX(anchorLeft);}float anchorRight = -(cardMargin + cardViewWidth);//向右滑动if (position < 1 && position > 0) {//0~anchorRightview.setTranslationX(position * anchorRight);float scaleFactor = (1 - position) * (1 - mMinScale) + mMinScale;
// view.setScaleX(scaleFactor);view.setScaleY(scaleFactor);view.setPivotX(pageWidth);view.setTranslationZ(-position);}//变为右页(相对于起始位置)if (position == 1) {view.setTranslationX(anchorRight);}}private void transformRightPage(View view, float position, float cardMargin, int cardViewWidth, int pageWidth) {if (isOutLimit(1, position)) {return;}
// Log.i("YinTest_", "右页 position=" + position + ",cardMargin = " + cardMargin);//初始状态 position=1.0,viewIndex = 2float anchorRight = -(cardMargin + cardViewWidth);//右页右边的锚点view.setTranslationZ(-position);view.setPivotX(0);float scaleFactor = (1 - position) * (1 - mMinScale) + mMinScale;//view.setScaleX(scaleFactor);view.setScaleY(scaleFactor);if (position == 1) {//初始状态view.setTranslationX(anchorRight);}//向左滑动if (position < 1 && position > 0) {//anchorRight ~ 0view.setTranslationX((position) * anchorRight);}//变为当左页(相对于起始位置)if (position == 0) {view.setTranslationX(0);}//向右滑动if (position > 1 && position < 2) {// anchorRight ~ -pageWidth*2view.setTranslationX((2-position)*anchorRight + (2*position-2) * -pageWidth);}//变为右页(相对于起始位置)if (position == 2) {view.setTranslationX(-pageWidth*2);}}private void transformMostRightPage(View view, float position, float cardMargin, int cardViewWidth, int pageWidth) {if (isOutLimit(2, position)) {return;}float startPosition = -pageWidth * 2;
// Log.i("YinTest_", "最右页 position=" + position + ",cardMargin = " + cardMargin);//初始状态 position=2.0float anchorRight = -(cardMargin + cardViewWidth);//右页右边的锚点view.setTranslationZ(-position);view.setPivotX(0);float scaleFactor = (1 - position) * (1 - mMinScale) + mMinScale;//view.setScaleX(scaleFactor);view.setScaleY(scaleFactor);//初始状态position=-2.0if (position == 2) {view.setTranslationX(startPosition);}//向左滑动 2~1if (position < 2 && position > 1) {//逆滑动 startPosition ~ anchorRight
// Log.i("YinTest_", " 最右页 向左滑动 position=" + position + ",translationX = " + (-position - 1));float translationX = (position - 1) * startPosition - (position - 2) * anchorRight;view.setTranslationX(translationX);}//变为左页(相对于起始位置)if (position == 1) {view.setTranslationX(anchorRight);}//向右滑动if (position > 2 && position < 3) {//startPosition~anchorLeft 保持其实际位置不变,不影响其他页面翻转
// Log.i("YinTest_", " 最左页 向左滑动 position=" + position + ",translationX = " + (-position - 1));view.setTranslationX(startPosition - (position - 2) * pageWidth);}//变为右页(相对于起始位置)if (position == 3) {//向右滑动保持不变,但变为右页后跳转到正常显示位置view.setTranslationX(0);}}public void setCurrentPageIndex(int index) {int currentPageIndex = index % dataSize;this.leftMostPageIndex = checkIndex(currentPageIndex, -2);this.leftPageIndex = checkIndex(currentPageIndex, -1);this.currentPageIndex = currentPageIndex;this.rightPageIndex = checkIndex(currentPageIndex, 1);this.rightMostPageIndex = checkIndex(currentPageIndex, 2);// Log.i("YinTest_", "setCurrentPageIndex " + leftMostPageIndex+"," + leftPageIndex+"," + currentPageIndex+"," + rightPageIndex+"," + rightMostPageIndex);}public int checkIndex(int index, int offset) {if ((index + offset) < 0) {return dataSize + index + offset;} else if ((index + offset) >= dataSize) {return index + offset - dataSize;} else {return index + offset;}}
}
完整Demo:
https://download.csdn.net/download/y280903468/89871333