效果图【录制后使用扣扣秀视频制作的gif,看见水印请别见怪】:
实现的主要注意点【关于view pager的使用就忽略了】
1、
Adapter需要重写函数——
@Override
public float getPageWidth(int position);
2、clipChildren属性的使用—-决定了一屏三页还是一屏两页,三页的就比如爱奇艺的横向滑动的左右两边有相互接壤的页面一部分,两页的就是效果图展示。
当前页所占屏幕宽度,不可以设置ViewPager属性clipToPadding=”false”
* 或者clipChildren=”false”,否则不起作用,设置clipToPadding=”false”同一屏幕将会出现三个页,true时仅有一个页。
3、
ShadowTransformer的使用。
下面上做过简要封装后的代码(代码中因为需要有三个部分的页面样式,故而有做过一个分组,具体可见Adapter抽象基类):
1) 定义接口:
public interface ICardViewPagerAdapter {
/*
用于计算阴影
*/
int MAX_ELEVATION_FACTOR = 8;
/*
CardView阴影
*/
float getBaseElevation();
View getCardViewAt(int position);
int getCount();
/**
是否使用阴影效果【主要针对CardView言】
false:
app:cardElevation="0px" //阴影大小
app:cardMaxElevation="2px"//最大阴影大小,该值最小2px
app:cardUseCompatPadding="false"//不显示阴影
app:contentPaddingBottom="-20dp"
app:contentPaddingTop="-20dp"
*/
boolean elevatieUsable();
}
2) Adapter基类实现
public abstract class CardPagerAdapter extends PagerAdapter implements ICardViewPagerAdapter {
private List mViews;
/**
* 数据源
*/
private List mResourceData;
private float mBaseElevation;
protected boolean isUsableEleVation = true;
protected TypeInflateView mTypeInflateView;
/**
* 子控件-亨元.
*/
private SparseArray viewWidgets = new SparseArray<>();
/**
* 缓存-避免多次新建对象
*/
private SparseArray rootViews = new SparseArray<>();
public boolean isUsableEleVation() {
return isUsableEleVation;
}
public void setUsableEleVation(boolean usableEleVation) {
isUsableEleVation = usableEleVation;
}
public CardPagerAdapter() {
mResourceData = new ArrayList<>();
mViews = new ArrayList<>();
}
public void addCardItem(T item) {
mViews.add(null);
mResourceData.add(item);
}
public void addAllCardItem(List allData){
mResourceData.addAll(allData);
int i = 0;
while (i < allData.size()){
mViews.add(null);
i++;
}
}
public View findWidgetViewById(View view , int resId){
View viewWidget = viewWidgets.get(resId);
if (viewWidget == null){
viewWidget = view.findViewById(resId);
viewWidgets.put(resId, viewWidget);
}
return viewWidget;
}
public float getBaseElevation() {
return mBaseElevation;
}
public enum TypeInflateView{
FirstPageType, CenterPageType, LastPageType
}
/**
* 当前页所占屏幕宽度,不可以设置ViewPager属性clipToPadding="false"
* 或者clipChildren="false",否则不起作用,设置clipToPadding="false"同一屏幕将会出现三个页,true时仅有一个页。
* @param position
* @return
*/
@Override
public float getPageWidth(int position) {
return (float) 0.63;
}
@Override
public View getCardViewAt(int position) {
return mViews.get(position);
}
@Override
public int getCount() {
return mResourceData.size();
}
@Override
public boolean elevatieUsable() {
return isUsableEleVation();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = rootViews.get(position);
if (view == null) {
if (position == 0) {
mTypeInflateView = TypeInflateView.FirstPageType;
view = LayoutInflater.from(container.getContext())
.inflate(onObtainLayoutR(mTypeInflateView, position), container, false);
} else if (getCount() - 1 == position) {
mTypeInflateView = TypeInflateView.LastPageType;
view = LayoutInflater.from(container.getContext())
.inflate(onObtainLayoutR(mTypeInflateView, position), container, false);
} else {
mTypeInflateView = TypeInflateView.CenterPageType;
view = LayoutInflater.from(container.getContext())
.inflate(onObtainLayoutR(mTypeInflateView, position), container, false);
}
rootViews.put(position, view);
}
container.addView(view);
bind(position, view);
View cardView = view.findViewById(onObtainCardViewRAtLayout());
if (mBaseElevation==0 && cardView!=null && cardView instanceof CardView) {
mBaseElevation = ((CardView)cardView).getCardElevation();
((CardView)cardView).setMaxCardElevation(mBaseElevation * MAX_ELEVATION_FACTOR);
}
if (mViews.get(position) == null) {
if (cardView != null)
mViews.set(position, cardView);
else
mViews.set(position, view);
}
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
mViews.set(position, null);
}
public View getRootView(int realPosition){
return rootViews.get(realPosition);
}
/**
* 此方法用于绑定数据到控件上面,以及设置事件监听等.
* @param position
* @param view
*/
public abstract void bind(int position, View view) ;
/**
* 此方法返回一个布局xml的id,eg:R.layout.
* @return
*/
protected abstract int onObtainLayoutR(TypeInflateView mTypeInflateView, int position);
/**
* 此方法用于获取CardView,必须在onObtainLayoutR()的layout中定义过CardView的id
* @return
*/
protected abstract int onObtainCardViewRAtLayout();
}
3)ShadowTransformer的实现类:
public class ShadowTransformer implements ViewPager.OnPageChangeListener, ViewPager.PageTransformer {
private ViewPager mViewPager;
private ICardViewPagerAdapter mAdapter;
private float mLastOffset;
private boolean mScalingEnabled; // 是否使用缩放效果,默认使用
private OnViewPageChangedListener mOnViewPageChangedListener;
public void setOnViewPageChangedListener(OnViewPageChangedListener zOnViewPageChangedListener){
this.mOnViewPageChangedListener = zOnViewPageChangedListener;
}
public ShadowTransformer(ViewPager viewPager, ICardViewPagerAdapter adapter) {
mViewPager = viewPager;
mViewPager.addOnPageChangeListener(this);
mAdapter = adapter;
}
public void enableScaling(boolean enable) {
if (mScalingEnabled && !enable) {
// shrink main card
View currentCard = mAdapter.getCardViewAt(mViewPager.getCurrentItem());
if (currentCard != null) {
currentCard.animate().scaleY(1);
currentCard.animate().scaleX(1);
}
}else if(!mScalingEnabled && enable){
// grow main card
View currentCard = mAdapter.getCardViewAt(mViewPager.getCurrentItem());
if (currentCard != null) {
currentCard.animate().scaleY(1.1f);
currentCard.animate().scaleX(1.1f);
}
}
mScalingEnabled = enable;
}
@Override
public void transformPage(View page, float position) {
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
int realCurrentPosition;
int nextPosition;
float baseElevation = mAdapter.getBaseElevation();
float realOffset;
boolean goingLeft = mLastOffset > positionOffset;
// If we're going backwards, onPageScrolled receives the last position
// instead of the current one
if (goingLeft) {
realCurrentPosition = position + 1;
nextPosition = position;
realOffset = 1 - positionOffset;
} else {
nextPosition = position + 1;
realCurrentPosition = position;
realOffset = positionOffset;
}
// Avoid crash on overscroll
if (nextPosition > mAdapter.getCount() - 1
|| realCurrentPosition > mAdapter.getCount() - 1) {
return;
}
// ((CardPagerAdapter)mAdapter).bind(realCurrentPosition,
// ((CardPagerAdapter)mAdapter).getRootView(realCurrentPosition));
// ((CardPagerAdapter)mAdapter).bind(nextPosition,
// ((CardPagerAdapter)mAdapter).getRootView(nextPosition));
View currentCard = mAdapter.getCardViewAt(realCurrentPosition);
// This might be null if a fragment is being used
// and the views weren't created yet
if (currentCard != null) {
if (mScalingEnabled) {
currentCard.setScaleX((float) (1 + 0.1 * (1 - realOffset)));
currentCard.setScaleY((float) (1 + 0.1 * (1 - realOffset)));
}
if (currentCard instanceof CardView) {
if (mAdapter.elevatieUsable()) {
((CardView)currentCard).setCardElevation((baseElevation + baseElevation
* (ICardViewPagerAdapter.MAX_ELEVATION_FACTOR - 1) * (1 - realOffset)));
} else {
((CardView)currentCard).setCardElevation(0.0f);
}
}
}
View nextCard = mAdapter.getCardViewAt(nextPosition);
// We might be scrolling fast enough so that the next (or previous) card
// was already destroyed or a fragment might not have been created yet
if (nextCard != null) {
if (mScalingEnabled) {
nextCard.setScaleX((float) (1 + 0.1 * (realOffset)));
nextCard.setScaleY((float) (1 + 0.1 * (realOffset)));
}
if (currentCard instanceof CardView) {
if (mAdapter.elevatieUsable()) {
((CardView)nextCard).setCardElevation((baseElevation + baseElevation
* (ICardViewPagerAdapter.MAX_ELEVATION_FACTOR - 1) * (realOffset)));
} else {
((CardView)currentCard).setCardElevation(0.0f);
}
}
}
mLastOffset = positionOffset;
if (mOnViewPageChangedListener != null)
mOnViewPageChangedListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
@Override
public void onPageSelected(int position) {
if (mOnViewPageChangedListener != null){
mOnViewPageChangedListener.onPageSelected(position);
}
}
@Override
public void onPageScrollStateChanged(int state) {
if (mOnViewPageChangedListener != null){
mOnViewPageChangedListener.onPageScrollStateChanged(state);
}
}
public interface OnViewPageChangedListener{
void onPageSelected(int position);
void onPageScrollStateChanged(int state);
void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
}
}
使用例子eg:
mCardActShopAdapter = new CardActShopAdapter();
mCardActShopAdapter.addCardItem("");
mCardActShopAdapter.addCardItem("");
mCardActShopAdapter.addCardItem("");
mCardActShopAdapter.addCardItem("");
mCardActShopAdapter.addCardItem("");
mCardShadowTransformer = new ShadowTransformer(viewPager, mCardActShopAdapter);
/**
* 是否启用滑动动画
*/
mCardShadowTransformer.enableScaling(true);
viewPager.setPageTransformer(false, mCardShadowTransformer);
/**
* 页面之间的间距
*/
viewPager.setPageMargin(getResources().getDimensionPixelOffset(R.dimen.dp_35));
//viewPager.setAllowSlidingToLastPosition(true);
viewPager.setOffscreenPageLimit(3);
viewPager.setAdapter(mCardActShopAdapter);
CardActShopAdapter是抽象基类的子类.根据需求自行进行扩展:
上一个简单例子:
public class CardActShopAdapter extends CardPagerAdapter {
public SparseArray mCenterViewHolder = new SparseArray<>();
private void bindDataForFirstView(View varView){
TextView tvTitleActivityCard = (TextView) findWidgetViewById(varView, R.id.tv_title_activity_card);
TextView tvDescActivityCard = (TextView) findWidgetViewById(varView, R.id.tv_desc_activity_card);
RelativeLayout rlBuyCare = (RelativeLayout) findWidgetViewById(varView, R.id.rl_buy_care);
tvDescActivityCard.setMovementMethod(ScrollingMovementMethod.getInstance());
rlBuyCare.setOnClickListener(new OnForbidDoubleClick() {
@Override
public void onClickSuccess(View varView) {
final ShoppingIntroductionDialog mShoppingIntroductionDialog = new ShoppingIntroductionDialog
.IntroductionBuilder(CardActShopActivity.this)
.create()
.showDialog();
mShoppingIntroductionDialog.findWidgetByResId(R.id.btn_back_page)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mShoppingIntroductionDialog.isShowing()){
mShoppingIntroductionDialog.dismiss();
}
}
});
}
@Override
public void onClickForbid(View varView) {
}
});
}
private void bindDataForCenterView(int position, View varView){
if (mCenterViewHolder.get(position) == null) {
ViewHolder viewHolder = new ViewHolder();
viewHolder.ivActivityCardHeader = (ImageView) findWidgetViewById(varView, R.id.iv_activity_card_header);
viewHolder.tvTitleActivityCard = (TextView) findWidgetViewById(varView, R.id.tv_title_activity_card);
viewHolder.tvDescActivityCard = (TextView) findWidgetViewById(varView, R.id.tv_desc_activity_card);
viewHolder.rlBuyCare = (TextView) findWidgetViewById(varView, R.id.tv_right_now_buy);
viewHolder.rlBuyCare.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ToastUtils.showLong("立即购买");
}
});
mCenterViewHolder.put(position, viewHolder);
}
}
private void bindDataForLastView(View varView){
TextView tvRightNowCall = (TextView) findWidgetViewById(varView, R.id.tv_right_now_call);
tvRightNowCall.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ToastUtils.showLong("客服电话:0871-xxx-xXXX");
}
});
}
@Override
public void bind(int position, View view) {
if (position == 0){
bindDataForFirstView(view);
} else if (position == getCount()-1){
bindDataForLastView(view);
} else {
bindDataForCenterView(position, view);
}
}
@Override
protected int onObtainLayoutR(TypeInflateView mTypeInflateView, int position) {
if (mTypeInflateView == TypeInflateView.FirstPageType){
return R.layout.pager_act_first;
} else if (mTypeInflateView == TypeInflateView.LastPageType){
return R.layout.pager_act_last;
} else {
return R.layout.pager_act_center;
}
}
@Override
protected int onObtainCardViewRAtLayout() {
return 0;
}
}