热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

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

这篇文章主要为大家详细介绍了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  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布局

<&#63;xml version="1.0" encoding="utf-8"&#63;>




 

  

   

代码中的使用

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 

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

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

源码:github源码

源码中的TestCardFragment 为使用模板

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


推荐阅读
author-avatar
手机用户2502928867
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有