千家信息网

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

发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,这篇文章将为大家详细讲解有关Android如何实现3D层叠式卡片图片展示,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。整体实现思路1、重写RelativeLayou
千家信息网最后更新 2025年11月07日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); }}

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

使用方法

    

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

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

//事件处理 @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布局

      

代码中的使用

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

关于"Android如何实现3D层叠式卡片图片展示"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

布局 卡片 图片 数据 比例 处理 代码 篇文章 图片展示 接下来 事件 位置 坐标 时候 更多 正在 支持 不错 实用 也就是 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 mac 下数据库建模工具 win7网站服务器 迷你玩家造mc玩家服务器 杭州app软件开发解决方案 数据量大的数据库硬件配置 hp 迷你服务器 徐人凤数据库2008答案 数据库中怎么设置指定日期前 安全的传奇服务器 卓茵科技互联网 面向对象软件开发什么设计 数据库插入数据太慢怎么办 数据库管理系统存取流程 六年级网络安全手抄报模板 王者荣耀战队服务器排名 500服务器错误服务器内部错误 小学网络安全领导职责 大学生软件开发社会实践报告 如何正确理解网络安全的意义 淘宝挂服务器可以吗 电子商务网络安全支付研究意义 网络安全和信息化工作任务清单 数据库查找数据方法 软件本地服务器部署项目教程 软件开发常见模式 网易我的手世界进入服务器教程 国内的时间服务器 网络安全专项检查动员部署会 图书馆服务器管理 小学生网络安全绘画超简单
0