Android realizes 3D laminated card image display

This example shares the specific code for Android to realize 3D laminated card image display for your reference. The specific contents are as follows

Look at the effect first

Well, look at the effect. Look down if you are interested!

Overall realization idea

1. Override relativelayout to lock the relativelayout of width height ratio

2. Customize a panel that supports sliding and inherit ViewGroup

3. Card view drawing

4. Use layout in page

First, in order to better show the picture, we rewrite the relativelayout and write a relativelayout that locks the width height ratio

AutoScaleRelativeLayout

public class AutoScaleRelativeLayout extends RelativeLayout {
 //宽高比例
 private float widthHeightRate = 0.35f;

 public AutoScaleRelativeLayout(Context context) {
  this(context,null);
 }

 public AutoScaleRelativeLayout(Context context,AttributeSet attrs) {
  this(context,attrs,0);
 }

 public AutoScaleRelativeLayout(Context context,AttributeSet attrs,int defStyleAttr) {
  super(context,defStyleAttr);
  //通过布局获取宽高比例
  TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.card,0);
  widthHeightRate = a.getFloat(R.styleable.card_widthHeightRate,widthHeightRate);
  a.recycle();
 }

 @Override
 protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec,heightMeasureSpec);

  // 调整高度
  int width = getMeasuredWidth();
  int height = (int) (width * widthHeightRate);
  ViewGroup.LayoutParams lp = getLayoutParams();
  lp.height = height;
  setLayoutParams(lp);
 }
}

In this way, we have written the parent layout we want

usage method

<com.petterp.toos.ImageCard.AutoScaleRelativeLayout
  android:id="@+id/card_top_layout"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  card:widthHeightRate="0.6588">
<!--  widthHeightRate:就是设置宽高的百分比-->
  <ImageView
   android:id="@+id/card_image_view"
   android:layout_width="fill_parent"
   android:layout_height="match_parent"
   android:scaleType="fitXY" />
<!--    这是我们展示的图片-->
  <View
   android:id="@+id/maskView"
   android:layout_width="fill_parent"
   android:layout_height="match_parent"
   android:background="?android:attr/selectableItemBackground"
   android:clickable="true" />
<!--  这个是为了让我们图片上有波纹-->
</com.petterp.toos.ImageCard.AutoScaleRelativeLayout>

Next is the main layout, that is, the layout of the display pictures

In order to realize sliding, we write a drawing board that supports sliding

//事件处理
 @Override
 public boolean dispatchTouchEvent(MotionEvent ev) {
  int action = ev.getActionMasked();
  // 按下时保存坐标信息
  if (action == MotionEvent.ACTION_DOWN) {
   this.downPoint.x = (int) ev.getX();
   this.downPoint.y = (int) ev.getY();
  }
  return super.dispatchTouchEvent(ev);
 }

 /* touch事件的拦截与处理都交给mDraghelper来处理 */
 @Override
 public boolean onInterceptTouchEvent(MotionEvent ev) {
  boolean shouldIntercept = mDragHelper.shouldInterceptTouchEvent(ev);
  boolean moveFlag = moveDetector.onTouchEvent(ev);
  int action = ev.getActionMasked();
  if (action == MotionEvent.ACTION_DOWN) {
   // ACTION_DOWN的时候就对view重新排序
   if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_SETTLING) {
    mDragHelper.abort();
   }
   orderViewStack();

   // 保存初次按下时arrowFlagView的Y坐标
   // action_down时就让mDragHelper开始工作,否则有时候导致异常
   mDragHelper.processTouchEvent(ev);
  }

  return shouldIntercept && moveFlag;
 }

 @Override
 public boolean onTouchEvent(MotionEvent e) {
  try {
   // 统一交给mDragHelper处理,由DragHelperCallback实现拖动效果
   // 该行代码可能会抛异常,正式发布时请将这行代码加上try catch
   mDragHelper.processTouchEvent(e);
  } catch (Exception ex) {
   ex.printStackTrace();
  }
  return true;
 }
 //计算
 @Override
 protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
  measureChildren(widthMeasureSpec,heightMeasureSpec);
  int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
  int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
  setMeasuredDimension(
    resolveSizeAndState(maxWidth,widthMeasureSpec,0),resolveSizeAndState(maxHeight,heightMeasureSpec,0));

  allWidth = getMeasuredWidth();
  allHeight = getMeasuredHeight();
 }
 //定位
 @Override
 protected void onLayout(boolean changed,int left,int top,int right,int bottom) {
  // 布局卡片view
  int size = viewList.size();
  for (int i = 0; i < size; i++) {
   View viewItem = viewList.get(i);
   int childHeight = viewItem.getMeasuredHeight();
   int viewLeft = (getWidth() - viewItem.getMeasuredWidth()) / 2;
   viewItem.layout(viewLeft,itemMarginTop,viewLeft + viewItem.getMeasuredWidth(),itemMarginTop + childHeight);
   int offset = yOffsetStep * i;
   float scale = 1 - SCALE_STEP * i;
   if (i > 2) {
    // 备用的view
    offset = yOffsetStep * 2;
    scale = 1 - SCALE_STEP * 2;
   }

   viewItem.offsetTopAndBottom(offset);
   viewItem.setScaleX(scale);
   viewItem.setScaleY(scale);
  }

  // 布局底部按钮的View
  if (null != bottomLayout) {
   int layoutTop = viewList.get(0).getBottom() + bottomMarginTop;
   bottomLayout.layout(left,layoutTop,right,layoutTop
     + bottomLayout.getMeasuredHeight());
  }

  // 初始化一些中间参数
  initCenterViewX = viewList.get(0).getLeft();
  initCenterViewY = viewList.get(0).getTop();
  childWith = viewList.get(0).getMeasuredWidth();
 }
  //onFinishInflate 当View中所有的子控件均被映射成xml后触发
 @Override
 protected void onFinishInflate() {
  super.onFinishInflate();
  // 渲染完成,初始化卡片view列表
  viewList.clear();
  int num = getChildCount();
  for (int i = num - 1; i >= 0; i--) {
   View childView = getChildAt(i);
   if (childView.getId() == R.id.card_bottom_layout) {
    bottomLayout = childView;
    initBottomLayout();
   } else {
    // for循环取view的时候,是从外层往里取
    CardItemView viewItem = (CardItemView) childView;
    viewItem.setParentView(this);
    viewItem.setTag(i + 1);
    viewItem.maskView.setOnClickListener(btnListener);
    viewList.add(viewItem);
   }
  }

  CardItemView bottomCardView = viewList.get(viewList.size() - 1);
  bottomCardView.setAlpha(0);
 }

Card view drawing

private void initSpring() {
  SpringConfig springConfig = SpringConfig.fromBouncinessAndSpeed(15,20);
  SpringSystem mSpringSystem = SpringSystem.create();
  springX = mSpringSystem.createSpring().setSpringConfig(springConfig);
  springY = mSpringSystem.createSpring().setSpringConfig(springConfig);

  springX.addListener(new SimpleSpringListener() {
   @Override
   public void onSpringUpdate(Spring spring) {
    int xPos = (int) spring.getCurrentValue();
    setScreenX(xPos);
    parentView.onViewPosChanged(CardItemView.this);
   }
  });

  springY.addListener(new SimpleSpringListener() {
   @Override
   public void onSpringUpdate(Spring spring) {
    int yPos = (int) spring.getCurrentValue();
    setScreenY(yPos);
    parentView.onViewPosChanged(CardItemView.this);
   }
  });
 }
 //装载数据
 public void fillData(CardDataItem itemData) {
  Glide.with(getContext()).load(itemData.imagePath).into(imageView);

 }
 /**
  * 动画移动到某个位置
  */
 public void animTo(int xPos,int yPos) {
  setCurrentSpringPos(getLeft(),getTop());
  springX.setEndValue(xPos);
  springY.setEndValue(yPos);
 }

 /**
  * 设置当前spring位置
  */
 private void setCurrentSpringPos(int xPos,int yPos) {
  springX.setCurrentValue(xPos);
  springY.setCurrentValue(yPos);
 }

Next, we need to use it to write the fragment layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:card="http://schemas.android.com/apk/res-auto"
    android:background="#fff"
    android:orientation="vertical">

 <com.petterp.toos.ImageCard.CardSlidePanel
  android:id="@+id/image_slide_panel"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  card:bottomMarginTop="38dp"
  card:itemMarginTop="10dp"
  card:yOffsetStep="26dp">

  <LinearLayout
   android:id="@+id/card_bottom_layout"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:gravity="center"
   android:orientation="horizontal">

   <Button
    android:background="#03A9F4"
    android:text="右侧移除"
    android:id="@+id/card_left_btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
   />

   <Button
    android:background="#03A9F4"
    android:text="右侧移除"
    android:id="@+id/card_right_btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="10dp"
    />
  </LinearLayout>

  <com.petterp.toos.ImageCard.CardItemView
   android:layout_width="match_parent"
   android:layout_height="wrap_content" />

  <com.petterp.toos.ImageCard.CardItemView
   android:layout_width="match_parent"
   android:layout_height="wrap_content" />

  <com.petterp.toos.ImageCard.CardItemView
   android:layout_width="match_parent"
   android:layout_height="wrap_content" />

  <com.petterp.toos.ImageCard.CardItemView
   android:layout_width="match_parent"
   android:layout_height="wrap_content" />

 </com.petterp.toos.ImageCard.CardSlidePanel>

</LinearLayout>

Use in code

private void initView(View rootView) {
  CardSlidePanel slidePanel = (CardSlidePanel) rootView
    .findViewById(R.id.image_slide_panel);
  cardSwitchListener = new CardSlidePanel.CardSwitchListener() {

   @Override
   public void onShow(int index) {
    Toast.makeText(getContext(),"CardFragment"+"正在显示=" +index,Toast.LENGTH_SHORT).show();

   }
   //type 0=右边 ,-1=左边
   @Override
   public void onCardVanish(int index,int type) {
    Toast.makeText(getContext(),"CardFragment"+ "正在消失=" + index + " 消失type=" + type,Toast.LENGTH_SHORT).show();
   }

   @Override
   public void onItemClick(View cardView,int index) {
    Toast.makeText(getContext(),"CardFragment"+"卡片点击=" + index,Toast.LENGTH_SHORT).show();
   }
  };
  slidePanel.setCardSwitchListener(cardSwitchListener);
  prepareDataList();
  slidePanel.fillData(dataList);
 }
 //封装数据
 private void prepareDataList() {
  int num = imagePaths.length;
  //重复添加数据10次(测试数据太少)
  for (int j = 0; j < 10; j++) {
   for (int i = 0; i < num; i++) {
    CardDataItem dataItem = new CardDataItem();
    dataItem.imagePath = imagePaths[i];
    dataList.add(dataItem);
   }
  }
 }

At this point, the main logic code has been written

Source code: GitHub source code

The testcardfragment in the source code is a template

The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>