Android realizes 3D cascade card image display

Time:2021-5-11

In this paper, we share the specific code of 3D cascade card image display with Android for your reference. The specific content is as follows

Let’s see the effect first

Well, the effect of watching, interested in looking down Oh!

Overall realization idea

1. Rewriting relativelayout to realize relative layout of locking width to height ratio

2. Customize a sliding panel to inherit ViewGroup

3. Card view drawing

4. Using layout in a page

First of all, in order to show the picture better, let’s rewrite relativelayout to write a relativelayout that locks the ratio of width to height

AutoScaleRelativeLayout

public class AutoScaleRelativeLayout extends RelativeLayout {
 //Width to height ratio
 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, attrs, defStyleAttr);
  //Get width height ratio through layout
  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.card, 0, 0);
  widthHeightRate = a.getFloat(R.styleable.card_widthHeightRate, widthHeightRate);
  a.recycle();
 }

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

  //Adjust the height
  int width = getMeasuredWidth();
  int height = (int) (width * widthHeightRate);
  ViewGroup.LayoutParams lp = getLayoutParams();
  lp.height = height;
  setLayoutParams(lp);
 }
}

So we’ve 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">
<!--   Widthhightreate: set the percentage of width to height -- >
  <ImageView
   android:id="@+id/card_image_view"
   android:layout_width="fill_parent"
   android:layout_height="match_parent"
   android:scaleType="fitXY" />
<!--     Here's the picture we're showing -- >
  <View
   android:id="@+id/maskView"
   android:layout_width="fill_parent"
   android:layout_height="match_parent"
   android:background="?android:attr/selectableItemBackground"
   android:clickable="true" />
<!--   This is to make our picture wavy -- >
</com.petterp.toos.ImageCard.AutoScaleRelativeLayout>

Next is the main layout, which is to show the layout of the picture

In order to achieve sliding, we write a Sketchpad that supports sliding

//Event handling
 @Override
 public boolean dispatchTouchEvent(MotionEvent ev) {
  int action = ev.getActionMasked();
  //Save coordinate information when pressed
  if (action == MotionEvent.ACTION_DOWN) {
   this.downPoint.x = (int) ev.getX();
   this.downPoint.y = (int) ev.getY();
  }
  return super.dispatchTouchEvent(ev);
 }

 /*The interception and processing of touch events are all handled by 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_ Reorder views when down
   if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_SETTLING) {
    mDragHelper.abort();
   }
   orderViewStack();

   //Save the Y coordinate of the arrowflagview at the first press
   // action_ Let mdraghelper work when down, otherwise sometimes it will cause an exception
   mDragHelper.processTouchEvent(ev);
  }

  return shouldIntercept && moveFlag;
 }

 @Override
 public boolean onTouchEvent(MotionEvent e) {
  try {
   //Mdraghelper is responsible for the unified processing, and draghelper callback is responsible for the drag effect
   //This line of code may throw an exception. Please add try catch to this line of code when it is officially released
   mDragHelper.processTouchEvent(e);
  } catch (Exception ex) {
   ex.printStackTrace();
  }
  return true;
 }
 //Calculation
 @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();
 }
 //Positioning
 @Override
 protected void onLayout(boolean changed, int left, int top, int right,
       int bottom) {
  //Layout card 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) {
    //Alternate view
    offset = yOffsetStep * 2;
    scale = 1 - SCALE_STEP * 2;
   }

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

  //View of the buttons at the bottom of the layout
  if (null != bottomLayout) {
   int layoutTop = viewList.get(0).getBottom() + bottomMarginTop;
   bottomLayout.layout(left, layoutTop, right, layoutTop
     + bottomLayout.getMeasuredHeight());
  }

  //Initialize some intermediate parameters
  initCenterViewX = viewList.get(0).getLeft();
  initCenterViewY = viewList.get(0).getTop();
  childWith = viewList.get(0).getMeasuredWidth();
 }
  //Onfinishinflate is triggered when all child controls in the view are mapped to XML
 @Override
 protected void onFinishInflate() {
  super.onFinishInflate();
  //After rendering, initialize the card list
  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 {
    //When the for loop takes the view, it takes it from the outside to the inside
    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);
   }
  });
 }
 //Loading data
 public void fillData(CardDataItem itemData) {
  Glide.with(getContext()).load(itemData.imagePath).into(imageView);


 }
 /**
  *The animation moves to a position
  */
 public void animTo(int xPos, int yPos) {
  setCurrentSpringPos(getLeft(), getTop());
  springX.setEndValue(xPos);
  springY.setEndValue(yPos);
 }

 /**
  *Set current spring location
  */
 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= Remove right
    android:id="@+id/card_left_btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
   />


   <Button
    android:background="#03A9F4"
    android:text= Remove right
    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" + "showing =" + index, toast. Length "_ SHORT).show();

   }
   //Type 0 = right, - 1 = left
   @Override
   public void onCardVanish(int index, int type) {
    Toast. Maketext (getcontext(), "cardfragment" + "disappearing =" + index + "disappearing, type =" + type, toast. Length "_ SHORT).show();
   }

   @Override
   public void onItemClick(View cardView, int index) {
    Toast. Maketext (getcontext(), "cardfragment" + "card Click =" + index, toast. Length "_ SHORT).show();
   }
  };
  slidePanel.setCardSwitchListener(cardSwitchListener);
  prepareDataList();
  slidePanel.fillData(dataList);
 }
 //Encapsulate data
 private void prepareDataList() {
  int num = imagePaths.length;
  //Add data 10 times repeatedly (too little test data)
  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 is finished

Detailed description of the code has been annotated, all code please see the source code

Source code: GitHub source code

The testcardfragment in the source code is the use template

The above is the whole content of this article, I hope to help you learn, and I hope you can support developer more.