Android实现3D画廊效果
使用ViewPager打造的3D画廊,先看效果图:

1.中间item放大2.中间item覆盖在两侧item上3.点击或者滑动两侧的item可以切换ViewPager的当前展示页面
下面我们看代码怎么实现:
先看下布局,主界面只有一个RecyclerView就不贴代码了.
android:layout_width="match_parent"android:layout_height="match_parent"android:clipChildren="false"android:id="@+id/rl_vp_container"android:orientation="vertical">android:layout_toLeftOf="@+id/viewpager"android:id="@+id/view_left"android:layout_width="match_parent"android:layout_height="303dp"/>android:layout_toRightOf="@+id/viewpager"android:id="@+id/view_right"android:layout_width="match_parent"android:layout_height="303dp"/>android:layout_centerHorizontal="true"android:layout_width="200dp"android:layout_height="303dp"android:id="@+id/viewpager"/>android:layout_centerHorizontal="true"android:layout_below="@+id/viewpager"android:layout_marginTop="8dp"android:id="@+id/tv_star_desc"android:layout_gravity="center_horizontal"android:layout_width="wrap_content"android:layout_height="wrap_content"/>
android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center_horizontal"android:scaleX="0.85"android:scaleY="0.85"android:elevation="6dp">android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" >android:adjustViewBounds="true"android:id="@+id/iv_star_item"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="fitXY"/>android:layout_marginRight="6dp"android:layout_marginBottom="8dp"android:layout_alignParentRight="true"android:layout_alignParentBottom="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"android:background="#00000000">android:gravity="bottom"android:id="@+id/tv_index"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#FFFFFFFF"android:textSize="20sp"android:shadowDy="2"android:shadowDx="0"android:shadowRadius="4"android:text="2"android:shadowColor="#80000000"/>android:gravity="bottom"android:id="@+id/tv_star_total"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#FFFFFFFF"android:textSize="12sp"android:shadowDy="2"android:shadowDx="0"android:shadowRadius="4"android:text="/10"android:shadowColor="#80000000" />android:visibility="visible"android:id="@+id/iv_cover"android:src="@mipmap/bg_40black"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="centerCrop"/>
public class RotationPageTransformer implements ViewPager.PageTransformer{private static final float MIN_SCALE=0.85f;private static final float MIN_ALPHA=0.6f;public void setContext(Context context) {mContext = context;}private Context mContext;@Overridepublic void transformPage(View page, float position) {float scaleFactor = Math.max(MIN_SCALE,1 - Math.abs(position));float scaleAlpha = Math.max(MIN_ALPHA,1 - Math.abs(position));ImageView imageTag= (ImageView) page.findViewById(R.id.iv_cover);float rotate = 0;//position小于等于1的时候,代表page已经位于中心item的最左边,//此时设置为最小的缩放率以及最大的旋转度数if (position <= -1){page.setScaleX(MIN_SCALE);page.setScaleY(MIN_SCALE);imageTag.setAlpha((float) 1);}//position从0变化到-1,page逐渐向左滑动else if (position < 0){imageTag.setAlpha(Math.abs(position));page.setScaleX(scaleFactor);page.setScaleY(scaleFactor);}//position从0变化到1,page逐渐向右滑动else if (position >=0 && position < 1){imageTag.setAlpha(position);page.setScaleX(scaleFactor);page.setScaleY(scaleFactor);}//position大于等于1的时候,代表page已经位于中心item的最右边else if (position >= 1){imageTag.setAlpha((float)1);page.setScaleX(scaleFactor);page.setScaleY(scaleFactor);}}}
public class MainAdapter extends RecyclerView.Adapter {private Context mContext;private float downX ; //按下时 的X坐标private float downY ; //按下时 的Y坐标private int currentPosition;private int mOriginSize;private ListdataList=new ArrayList<>(); public MainAdapter(Context context,Listlist) { this.mContext=context;dataList.addAll(list);}@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = LayoutInflater.from(mContext).inflate(R.layout.layout_main_star1, parent, false);return new MainStarViewHolder(view);}@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {// 所以在空白的左右两侧各填充了透明的View(StarView自定义View拦截左右方向滑动事件),用于交互,左侧View向右滑动和点击ViewPager切换// ,右侧View向左滑动和点击切换ViewPager,其它不做处理final MainStarViewHolder mainStarHolder = (MainStarViewHolder) holder;mainStarHolder.mViewPager.setPageTransformer(true, new RotationPageTransformer());mainStarHolder.mViewPager.setOffscreenPageLimit(2);DisplayMetrics dm = mContext.getApplicationContext().getResources().getDisplayMetrics();//不同分辨率适配int width = dm.widthPixels;if (width > 800 && width <= 1080) {mainStarHolder.mViewPager.setPageMargin(-200);} else if (width > 1080) {mainStarHolder.mViewPager.setPageMargin(-280);} else {mainStarHolder.mViewPager.setPageMargin(-180);}mainStarHolder.viewLeft.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) { //左侧透明View仅在向右滑时切换ViewPagerfloat x= event.getX();float y = event.getY();switch (event.getAction()){case MotionEvent.ACTION_DOWN://将按下时的坐标存储downX = x;downY = y;break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL://获取到距离差float dx= x-downX;float dy = y-downY;//防止是按下也判断//通过距离差判断方向int orientation = getOrientation(dx, dy);switch (orientation) {case 'r': //向右滑动mainStarHolder.mViewPager.setCurrentItem(mainStarHolder.mViewPager.getCurrentItem()-1,true);return true;case '0': //点击mainStarHolder.mViewPager.setCurrentItem(mainStarHolder.mViewPager.getCurrentItem()-1,true);return true;case 'l': //向左滑动return true;}break;}return true;}});mainStarHolder.viewRight.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) { //右侧透明View仅在向右滑时切换ViewPagerfloat x= event.getX();float y = event.getY();switch (event.getAction()){case MotionEvent.ACTION_DOWN://将按下时的坐标存储downX = x;downY = y;break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL://获取到距离差float dx= x-downX;float dy = y-downY;//通过距离差判断方向int orientation = getOrientation(dx, dy);switch (orientation) {case 'r': //向右滑动return true;case '0': //点击mainStarHolder.mViewPager.setCurrentItem(mainStarHolder.mViewPager.getCurrentItem()+1,true);return true;case 'l': //向左滑动if(event.getAction()== MotionEvent.ACTION_UP || event.getAction()== MotionEvent.ACTION_CANCEL ){mainStarHolder.mViewPager.setCurrentItem(mainStarHolder.mViewPager.getCurrentItem()+1,true);}return true;}break;}return true;}});mOriginSize = dataList.size();initStarAdapter(mainStarHolder, dataList);mainStarHolder.mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@Overridepublic void onPageSelected(int position) {currentPosition = position;mainStarHolder.mViewPager.setTranslationX(1);}@Overridepublic void onPageScrollStateChanged(int state) {}});}@Overridepublic int getItemCount() {return 1;}private void initStarAdapter(MainStarViewHolder mainStarHolder, ListdataList) { final MainStarAdapter mainStarAdapter = new MainStarAdapter(dataList, mContext, mainStarHolder.mViewPager, mOriginSize);mainStarHolder.mViewPager.setAdapter(mainStarAdapter);mainStarHolder.mViewPager.setCurrentItem( 20*mOriginSize + currentPosition);}//获取滑动方向private int getOrientation(float dx, float dy) {if (Math.abs(dx)>Math.abs(dy)){//X轴移动if(dx==0){//点击return '0';}return dx>0?'r':'l';}else{//Y轴移动if(dy==0){//点击return '0';}return dy>0?'b':'t';}}}
public class CustomViewPager extends ViewPager {private ArrayListchildCenterXAbs = new ArrayList<>(); private SparseArraychildIndex = new SparseArray<>(); public CustomViewPager(Context context) {super(context);init();}public CustomViewPager(Context context, AttributeSet attrs) {super(context, attrs);init();}private void init(){setClipToPadding(false);setOverScrollMode(OVER_SCROLL_NEVER);}/*** @param childCount* @param n* @return 第n个位置的child 的绘制索引*/@Overrideprotected int getChildDrawingOrder(int childCount, int n) {if (n == 0 || childIndex.size() != childCount) {childCenterXAbs.clear();childIndex.clear();int viewCenterX = getViewCenterX(this);for (int i = 0; i < childCount; ++i) {int indexAbs = Math.abs(viewCenterX - getViewCenterX(getChildAt(i)));//两个距离相同,后来的那个做自增,从而保持abs不同if (childIndex.get(indexAbs) != null) {++indexAbs;}childCenterXAbs.add(indexAbs);childIndex.append(indexAbs, i);}Collections.sort(childCenterXAbs);//1,0,2 0,1,2}//那个item距离中心点远一些,就先draw它。(最近的就是中间放大的item,最后draw)return childIndex.get(childCenterXAbs.get(childCount - 1 - n));}private int getViewCenterX(View view) {int[] array = new int[2];view.getLocationOnScreen(array);return array[0] + view.getWidth() / 2;}}
评论
