软件编程
位置:首页>> 软件编程>> Android编程>> Android实现3D层叠式卡片图片展示

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

作者:倔强的菜鸟  发布时间:2022-04-22 16:39:19 

标签:Android,图片展示

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

先看效果

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

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

整体实现思路

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

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

3、卡片View绘制

4、页面中使用布局

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

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, attrs, defStyleAttr);
 //通过布局获取宽高比例
 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);

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

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

使用方法


<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>

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

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


//事件处理
@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);
}

卡片View绘制


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);
}

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


<?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>

代码中的使用


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);
  }
 }
}

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

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

源码:github源码

源码中的TestCardFragment 为使用模板

来源:https://blog.csdn.net/duihuapixiu/article/details/102795767

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com