Android实现3D层叠式卡片图片展示

前端之家收集整理的这篇文章主要介绍了Android实现3D层叠式卡片图片展示前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

本文实例为大家分享了Android实现3D层叠式卡片图片展示的具体代码,供大家参考,具体内容如下

先看效果

Android实现3D层叠式卡片图片展示


好了效果看了,感兴趣的往下看哦!

整体实现思路

1、重写RelativeLayout 实现 锁定宽高比例的 RelativeLayout

2、自定义一个支持滑动的面板 继承 ViewGroup

3、卡片View绘制

4、页面中使用布局

首先为了更好的展示图片我们重写一下 RelativeLayout 编写一个锁定宽高比例的 RelativeLayout

AutoScaleRelativeLayout

  1. public class AutoScaleRelativeLayout extends RelativeLayout {
  2. //宽高比例
  3. private float widthHeightRate = 0.35f;
  4.  
  5. public AutoScaleRelativeLayout(Context context) {
  6. this(context,null);
  7. }
  8.  
  9. public AutoScaleRelativeLayout(Context context,AttributeSet attrs) {
  10. this(context,attrs,0);
  11. }
  12.  
  13. public AutoScaleRelativeLayout(Context context,AttributeSet attrs,int defStyleAttr) {
  14. super(context,defStyleAttr);
  15. //通过布局获取宽高比例
  16. TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.card,0);
  17. widthHeightRate = a.getFloat(R.styleable.card_widthHeightRate,widthHeightRate);
  18. a.recycle();
  19. }
  20.  
  21. @Override
  22. protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
  23. super.onMeasure(widthMeasureSpec,heightMeasureSpec);
  24.  
  25. // 调整高度
  26. int width = getMeasuredWidth();
  27. int height = (int) (width * widthHeightRate);
  28. ViewGroup.LayoutParams lp = getLayoutParams();
  29. lp.height = height;
  30. setLayoutParams(lp);
  31. }
  32. }

这样我们就编写好了我们想要的父布局

使用方法

  1. <com.petterp.toos.ImageCard.AutoScaleRelativeLayout
  2. android:id="@+id/card_top_layout"
  3. android:layout_width="match_parent"
  4. android:layout_height="wrap_content"
  5. card:widthHeightRate="0.6588">
  6. <!-- widthHeightRate:就是设置宽高的百分比-->
  7. <ImageView
  8. android:id="@+id/card_image_view"
  9. android:layout_width="fill_parent"
  10. android:layout_height="match_parent"
  11. android:scaleType="fitXY" />
  12. <!-- 这是我们展示的图片-->
  13. <View
  14. android:id="@+id/maskView"
  15. android:layout_width="fill_parent"
  16. android:layout_height="match_parent"
  17. android:background="?android:attr/selectableItemBackground"
  18. android:clickable="true" />
  19. <!-- 这个是为了让我们图片上有波纹-->
  20. </com.petterp.toos.ImageCard.AutoScaleRelativeLayout>

接下来就是主要布局,也就是展示图片的布局了

为了实现滑动我们编写一个支持滑动的画板

  1. //事件处理
  2. @Override
  3. public boolean dispatchTouchEvent(MotionEvent ev) {
  4. int action = ev.getActionMasked();
  5. // 按下时保存坐标信息
  6. if (action == MotionEvent.ACTION_DOWN) {
  7. this.downPoint.x = (int) ev.getX();
  8. this.downPoint.y = (int) ev.getY();
  9. }
  10. return super.dispatchTouchEvent(ev);
  11. }
  12.  
  13. /* touch事件的拦截与处理都交给mDraghelper来处理 */
  14. @Override
  15. public boolean onInterceptTouchEvent(MotionEvent ev) {
  16. boolean shouldIntercept = mDragHelper.shouldInterceptTouchEvent(ev);
  17. boolean moveFlag = moveDetector.onTouchEvent(ev);
  18. int action = ev.getActionMasked();
  19. if (action == MotionEvent.ACTION_DOWN) {
  20. // ACTION_DOWN的时候就对view重新排序
  21. if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_SETTLING) {
  22. mDragHelper.abort();
  23. }
  24. orderViewStack();
  25.  
  26. // 保存初次按下时arrowFlagView的Y坐标
  27. // action_down时就让mDragHelper开始工作,否则有时候导致异常
  28. mDragHelper.processTouchEvent(ev);
  29. }
  30.  
  31. return shouldIntercept && moveFlag;
  32. }
  33.  
  34. @Override
  35. public boolean onTouchEvent(MotionEvent e) {
  36. try {
  37. // 统一交给mDragHelper处理,由DragHelperCallback实现拖动效果
  38. // 该行代码可能会抛异常,正式发布时请将这行代码加上try catch
  39. mDragHelper.processTouchEvent(e);
  40. } catch (Exception ex) {
  41. ex.printStackTrace();
  42. }
  43. return true;
  44. }
  45. //计算
  46. @Override
  47. protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
  48. measureChildren(widthMeasureSpec,heightMeasureSpec);
  49. int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
  50. int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
  51. setMeasuredDimension(
  52. resolveSizeAndState(maxWidth,widthMeasureSpec,0),resolveSizeAndState(maxHeight,heightMeasureSpec,0));
  53.  
  54. allWidth = getMeasuredWidth();
  55. allHeight = getMeasuredHeight();
  56. }
  57. //定位
  58. @Override
  59. protected void onLayout(boolean changed,int left,int top,int right,int bottom) {
  60. // 布局卡片view
  61. int size = viewList.size();
  62. for (int i = 0; i < size; i++) {
  63. View viewItem = viewList.get(i);
  64. int childHeight = viewItem.getMeasuredHeight();
  65. int viewLeft = (getWidth() - viewItem.getMeasuredWidth()) / 2;
  66. viewItem.layout(viewLeft,itemMarginTop,viewLeft + viewItem.getMeasuredWidth(),itemMarginTop + childHeight);
  67. int offset = yOffsetStep * i;
  68. float scale = 1 - SCALE_STEP * i;
  69. if (i > 2) {
  70. // 备用的view
  71. offset = yOffsetStep * 2;
  72. scale = 1 - SCALE_STEP * 2;
  73. }
  74.  
  75. viewItem.offsetTopAndBottom(offset);
  76. viewItem.setScaleX(scale);
  77. viewItem.setScaleY(scale);
  78. }
  79.  
  80. // 布局底部按钮的View
  81. if (null != bottomLayout) {
  82. int layoutTop = viewList.get(0).getBottom() + bottomMarginTop;
  83. bottomLayout.layout(left,layoutTop,right,layoutTop
  84. + bottomLayout.getMeasuredHeight());
  85. }
  86.  
  87. // 初始化一些中间参数
  88. initCenterViewX = viewList.get(0).getLeft();
  89. initCenterViewY = viewList.get(0).getTop();
  90. childWith = viewList.get(0).getMeasuredWidth();
  91. }
  92. //onFinishInflate 当View中所有的子控件均被映射成xml后触发
  93. @Override
  94. protected void onFinishInflate() {
  95. super.onFinishInflate();
  96. // 渲染完成,初始化卡片view列表
  97. viewList.clear();
  98. int num = getChildCount();
  99. for (int i = num - 1; i >= 0; i--) {
  100. View childView = getChildAt(i);
  101. if (childView.getId() == R.id.card_bottom_layout) {
  102. bottomLayout = childView;
  103. initBottomLayout();
  104. } else {
  105. // for循环取view的时候,是从外层往里取
  106. CardItemView viewItem = (CardItemView) childView;
  107. viewItem.setParentView(this);
  108. viewItem.setTag(i + 1);
  109. viewItem.maskView.setOnClickListener(btnListener);
  110. viewList.add(viewItem);
  111. }
  112. }
  113.  
  114. CardItemView bottomCardView = viewList.get(viewList.size() - 1);
  115. bottomCardView.setAlpha(0);
  116. }

卡片View绘制

  1. private void initSpring() {
  2. SpringConfig springConfig = SpringConfig.fromBouncinessAndSpeed(15,20);
  3. SpringSystem mSpringSystem = SpringSystem.create();
  4. springX = mSpringSystem.createSpring().setSpringConfig(springConfig);
  5. springY = mSpringSystem.createSpring().setSpringConfig(springConfig);
  6.  
  7. springX.addListener(new SimpleSpringListener() {
  8. @Override
  9. public void onSpringUpdate(Spring spring) {
  10. int xPos = (int) spring.getCurrentValue();
  11. setScreenX(xPos);
  12. parentView.onViewPosChanged(CardItemView.this);
  13. }
  14. });
  15.  
  16. springY.addListener(new SimpleSpringListener() {
  17. @Override
  18. public void onSpringUpdate(Spring spring) {
  19. int yPos = (int) spring.getCurrentValue();
  20. setScreenY(yPos);
  21. parentView.onViewPosChanged(CardItemView.this);
  22. }
  23. });
  24. }
  25. //装载数据
  26. public void fillData(CardDataItem itemData) {
  27. Glide.with(getContext()).load(itemData.imagePath).into(imageView);
  28.  
  29. }
  30. /**
  31. * 动画移动到某个位置
  32. */
  33. public void animTo(int xPos,int yPos) {
  34. setCurrentSpringPos(getLeft(),getTop());
  35. springX.setEndValue(xPos);
  36. springY.setEndValue(yPos);
  37. }
  38.  
  39. /**
  40. * 设置当前spring位置
  41. */
  42. private void setCurrentSpringPos(int xPos,int yPos) {
  43. springX.setCurrentValue(xPos);
  44. springY.setCurrentValue(yPos);
  45. }

接下来我们需要使用它 编写Fragment布局

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. xmlns:card="http://schemas.android.com/apk/res-auto"
  6. android:background="#fff"
  7. android:orientation="vertical">
  8.  
  9. <com.petterp.toos.ImageCard.CardSlidePanel
  10. android:id="@+id/image_slide_panel"
  11. android:layout_width="match_parent"
  12. android:layout_height="match_parent"
  13. card:bottomMarginTop="38dp"
  14. card:itemMarginTop="10dp"
  15. card:yOffsetStep="26dp">
  16.  
  17. <LinearLayout
  18. android:id="@+id/card_bottom_layout"
  19. android:layout_width="fill_parent"
  20. android:layout_height="wrap_content"
  21. android:gravity="center"
  22. android:orientation="horizontal">
  23.  
  24. <Button
  25. android:background="#03A9F4"
  26. android:text="右侧移除"
  27. android:id="@+id/card_left_btn"
  28. android:layout_width="wrap_content"
  29. android:layout_height="wrap_content"
  30. />
  31.  
  32. <Button
  33. android:background="#03A9F4"
  34. android:text="右侧移除"
  35. android:id="@+id/card_right_btn"
  36. android:layout_width="wrap_content"
  37. android:layout_height="wrap_content"
  38. android:layout_marginLeft="10dp"
  39. />
  40. </LinearLayout>
  41.  
  42. <com.petterp.toos.ImageCard.CardItemView
  43. android:layout_width="match_parent"
  44. android:layout_height="wrap_content" />
  45.  
  46. <com.petterp.toos.ImageCard.CardItemView
  47. android:layout_width="match_parent"
  48. android:layout_height="wrap_content" />
  49.  
  50. <com.petterp.toos.ImageCard.CardItemView
  51. android:layout_width="match_parent"
  52. android:layout_height="wrap_content" />
  53.  
  54. <com.petterp.toos.ImageCard.CardItemView
  55. android:layout_width="match_parent"
  56. android:layout_height="wrap_content" />
  57.  
  58. </com.petterp.toos.ImageCard.CardSlidePanel>
  59.  
  60. </LinearLayout>

代码中的使用

  1. private void initView(View rootView) {
  2. CardSlidePanel slidePanel = (CardSlidePanel) rootView
  3. .findViewById(R.id.image_slide_panel);
  4. cardSwitchListener = new CardSlidePanel.CardSwitchListener() {
  5.  
  6. @Override
  7. public void onShow(int index) {
  8. Toast.makeText(getContext(),"CardFragment"+"正在显示=" +index,Toast.LENGTH_SHORT).show();
  9.  
  10. }
  11. //type 0=右边 ,-1=左边
  12. @Override
  13. public void onCardVanish(int index,int type) {
  14. Toast.makeText(getContext(),"CardFragment"+ "正在消失=" + index + " 消失type=" + type,Toast.LENGTH_SHORT).show();
  15. }
  16.  
  17. @Override
  18. public void onItemClick(View cardView,int index) {
  19. Toast.makeText(getContext(),"CardFragment"+"卡片点击=" + index,Toast.LENGTH_SHORT).show();
  20. }
  21. };
  22. slidePanel.setCardSwitchListener(cardSwitchListener);
  23. prepareDataList();
  24. slidePanel.fillData(dataList);
  25. }
  26. //封装数据
  27. private void prepareDataList() {
  28. int num = imagePaths.length;
  29. //重复添加数据10次(测试数据太少)
  30. for (int j = 0; j < 10; j++) {
  31. for (int i = 0; i < num; i++) {
  32. CardDataItem dataItem = new CardDataItem();
  33. dataItem.imagePath = imagePaths[i];
  34. dataList.add(dataItem);
  35. }
  36. }
  37. }

到此主要逻辑代码就编写完了

详细说明代码中已经注释 ,全部代码请看源码

源码:github源码

源码中的TestCardFragment 为使用模板

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

猜你在找的Android相关文章