需要自定义一个组件CascadeLayout,让子view可以像拿扑克牌那样的层叠起来,主要实现效果:

为了设置子view之前的偏移距离,这里需要定义子view相对于上一张卡片的的左边距,上边距。然后每张卡片也可以单独的设置自己需要的边距。这个边距和不是指的内边距(padding)和外边距(margin),而是两张卡片之间的偏移距离。

在attrs中定义属性:

其中,Cascade属性集为组件对子view设置的统一属性,每个view默认使用两个属性定义的相对于上一张卡片的左边距和上边距;Cascade_LayoutParams属性集为子view单独为自己设置的对于上一张卡片的左边距和上边距,如果子view定义了这两个属性,则会覆盖掉CascadeLayout 定义的边距;

构造方法中读取这两个属性:

public CascadeLayout(Context context, AttributeSet attrs) {

super(context, attrs);

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.Cascade_LayoutParams);

try {

leftCardPadding = ta.getDimensionPixelSize(R.styleable.Cascade_leftCardPadding, context.getResources().getDimensionPixelSize(R.dimen.default_leftCardPadding));

topCardPadding = ta.getDimensionPixelSize(R.styleable.Cascade_topCardPadding, context.getResources().getDimensionPixelSize(R.dimen.default_leftCardPadding));

Log.e("TAG", "leftCardPadding:" + leftCardPadding);

Log.e("TAG", "topCardPadding:" + topCardPadding);

} finally {

if (ta != null) ta.recycle();

}

}

同样的,构造CascadeLayout.LayoutParams 来读取子view单独设置的属性:layoutLeftCardPadding,layoutTopCardPadding:

public static class LayoutParams extends ViewGroup.LayoutParams {

int x, y;//相对于father的位置

int layoutLeftCardPadding;//自己需要显示的左边的尺寸

int layoutTopCardPadding;//自己需要显示的上边的尺寸

public LayoutParams(Context c, AttributeSet attrs) {

super(c, attrs);

TypedArray ta = c.obtainStyledAttributes(attrs, R.styleable.Cascade_LayoutParams);

try {

layoutLeftCardPadding = ta.getDimensionPixelSize(R.styleable.Cascade_LayoutParams_layout_leftCardPadding, -1);

layoutTopCardPadding = ta.getDimensionPixelSize(R.styleable.Cascade_LayoutParams_layout_topCardPadding, -1);

Log.e("TAG", "leftCardPadding:" + layoutLeftCardPadding);

Log.e("TAG", "topCardPadding:" + layoutTopCardPadding);

} finally {

if (ta != null) ta.recycle();

}

}

public LayoutParams(int width, int height) {

super(width, height);

}

public LayoutParams(ViewGroup.LayoutParams source) {

super(source);

}

}

LayoutParams的x,y用于保存自己在CascadeLayout中的位置。

属性设定好之后,就可以通过onMeasure方法和onLayout方法来计算尺寸和布局。

onMeasure方法除了需要计算自己的尺寸之外,还需要需要计算每一个子view的尺寸和位置。计算的时候,如果不是最后一张card,则总宽度累加一个偏移距离,最后一张不累加。然后如果有子view单独为自己设置了距离上一张卡片的边距,则覆盖CascadeLayout设置的值。

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int width = getPaddingLeft(), height = getPaddingTop();

int count = getChildCount();

for (int i = 0; i < count; i++) {

View child = getChildAt(i);

measureChild(child, widthMeasureSpec, heightMeasureSpec);

LayoutParams params = (LayoutParams) child.getLayoutParams();

//计算下一张card的左边距和上边距

int cardPaddingLeft = params.layoutLeftCardPadding > 0 ? params.layoutLeftCardPadding : leftCardPadding;

int cardPaddingTop = params.layoutTopCardPadding > 0 ? params.layoutTopCardPadding : topCardPadding;

//保存子view的位置

params.x = width;

params.y = height;

//累加的width和height

if (i != count - 1) {

width += cardPaddingLeft;

height += cardPaddingTop;

} else {//最后一张

width += getPaddingRight() + child.getMeasuredWidth();

height += getPaddingBottom() + child.getMeasuredHeight();

}

}

/**

* resolveSize 和getDefaultSize有什么区别?

*

* getDefaultSize(size,measureSpec)优先使用measureSpec定义的大小;

* resolveSize(size,measureSpec),如果measureSpec未定义,则使用提供的大小(size),

* 否则,如果measureSpec的模式是(EXACTLY),则使用measureSpec定义的大小,

* 如果measureSpec定义的是AT_MOST,则使用两者中较小的那个

*

* 区别是当measureSpec定义的是AT_MOST(布局中为WRAP_CONTENT)的时候,getDefaultSize使用的是measureSpec定义的大小,

* resolveSize使用的是两者中较小的那个

*/

/**

* 那么这里的话,如果是WRAP_CONTENT的话,则应该使用较小的那个,使用resolveSize更为妥当

*/

setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec));

// setMeasuredDimension(getDefaultSize(width, widthMeasureSpec), getDefaultSize(height, heightMeasureSpec));

}

测量完之后,可以编写onLayout()了:

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

int count = getChildCount();

for (int i = 0; i < count; i++) {

View child = getChildAt(i);

LayoutParams params = (LayoutParams) child.getLayoutParams();

child.layout(params.x, params.y, params.x + child.getMeasuredWidth(), params.y + child.getMeasuredHeight());

}

}

最后,自定义LayoutParams需要重写以下方法,可直接从android源码中复制过来。

/**

* 自定义LayoutParams 需要重写以下方法

*/

@Override

protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {

return p instanceof CascadeLayout.LayoutParams;

}

@Override

protected ViewGroup.LayoutParams generateDefaultLayoutParams() {

return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

}

@Override

public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {

return new LayoutParams(getContext(), attrs);

}

@Override

protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {

return new LayoutParams(p);

}

以上内容已完整记录自定义CascadeLayout的处理过程。为了美观,这里在使用的时候给子view添加了一个动画效果,其中应用到了LayoutAnimationController类,用于为子视图添加动画效果,让卡片一张接一张的显示出来。

MainActivtiy:

void testLayoutAnimation() {

cascadeLayout = (CascadeLayout) findViewById(R.id.cl1);

AnimationSet set = new AnimationSet(true);

Animation alphaAnimation = new AlphaAnimation(0f, 1f);

alphaAnimation.setDuration(300);

set.addAnimation(alphaAnimation);

Animation scaleAnimation = new ScaleAnimation(0f, 1f, 0f, 1f, 0.5f, 0.5f);

scaleAnimation.setDuration(300);

set.addAnimation(scaleAnimation);

LayoutAnimationController controller = new LayoutAnimationController(set, 0.2f);

cascadeLayout.setLayoutAnimation(controller);

}

测试使用的布局文件:

xmlns:phy="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:id="@+id/cl1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:background="#cccccc"

phy:leftCardPadding="20dp"

phy:topCardPadding="30dp">

android:layout_width="100dp"

android:layout_height="200dp"

android:background="#ff0000" />

android:layout_width="100dp"

android:layout_height="200dp"

android:background="#ff0033" />

android:layout_width="100dp"

android:layout_height="200dp"

android:background="#ff0066"

phy:layout_leftCardPadding="50dp"

phy:layout_topCardPadding="80dp" />

android:layout_width="100dp"

android:layout_height="200dp"

android:background="#ff00aa" />

Android扑克牌抽奖View,android自定义层级view,扑克牌堆叠效果,cascadeLayout相关推荐

  1. Android签名背景颜色,Android UI设计系列之自定义DrawView组件实现数字签名效果(5)...

    最近项目中有个新的需求,用户在完交易需要进行输入支付密码付款的时候,要让用户签下自己的签名,提起到数字签名这个东西,感觉有点高大上,后来想想数字签名的原理也不是太复杂,主要实现原理就是利用了View的 ...

  2. Android基础控件——ProgressBar自定义的介绍、动画效果实现、附加三个漂亮的进度条

    ProgressBar自定义的介绍.动画效果实现.附加三个漂亮的进度条 shape属性介绍: corners 圆角   gradient 渐变   padding 内容离边界距离   size 大小 ...

  3. android的三个基础控件,Android基础控件——ProgressBar自定义的介绍、动画效果实现、附加三个漂亮的进度条...

    xml文件: android:centerColor="#00ff00" android:endColor="#0000ff" android:startCol ...

  4. Android:手把手教你自定义头像View,可根据名字自动生成背景色+文字的显示效果,含动画效果。

    首先看需要做成的效果,如下所示

  5. android layout include merge,Android 布局优化之include与merge

    Android 官方提供了三个用来优化布局的标签,分别是include.merge与ViewStub,其中ViewStub是动态加载视图到内存,大家可以查阅:Android UI布局优化之ViewSt ...

  6. android录制mp3音频,Android MP3录制,波形显示,音频权限兼容与播放

    我又来掀桌子了(ノಠ益ಠ)ノ彡┻━┻,这次是MP3录制和显示声音波形的一个故事. 先看看效果┑( ̄Д  ̄)┍ 2 1 MP3录制的逻辑过程就忽略了(真的不是因为懒(.・・)ノ),这里用的是开源的And ...

  7. android sqlite自定义函数,Android中自定义一个View的方法详解

    本文实例讲述了Android中自定义一个View的方法.分享给大家供大家参考,具体如下: Android中自定义View的实现比较简单,无非就是继承父类,然后重载方法,即便如此,在实际编码中难免会遇到 ...

  8. android minheight的作用,Android 自定义 View 最少必要知识

    1. 什么是自定义 View? 1.1 定义 在 Android 系统中,界面中所有能看到的元素都是 View.默认情况下,Android 系统为开发者提供了很多 View,比如用于展示文本信息的 T ...

  9. android炫酷的自定义view,Android自定义View实现炫酷进度条

    本文实例为大家分享了Android实现炫酷进度条的具体代码,供大家参考,具体内容如下 下面我们来实现如下效果: 第一步:创建attrs文件夹,自定义属性: 第二步:自定义View: /** * Cre ...

最新文章

  1. 1020 Tree Traversals
  2. poj1364(差分约束+Bellman-ford)
  3. 每天一个linux命令(25):linux文件属性详解
  4. 洛谷 P1678 烦恼的高考志愿
  5. c语言字符串去重简单,C语言实现简单飞机大战
  6. 关于web爬虫的tips
  7. Magento微信支付接口开发小记
  8. 非root用户ssh 执行 sudo远程机器免密钥
  9. Wireshark 检索命令
  10. 如何隐藏所有的导航栏
  11. [python]练习之判断3个数值中最大值
  12. 高通IPQ4019 IPQ4029 模块+底板双频 AC无线路由模块开发板
  13. MSC-51单片机原理与实践——第四章习题及答案解析
  14. 浅谈企业网站建设注意事项
  15. 整理2020智能车竞赛网站各分赛区报名情况
  16. MacBookPro阻止电脑自动下载更新
  17. 中国设备工程杂志中国设备工程杂志社中国设备工程编辑部2022年第18期目录
  18. psi-pred安装及预测蛋白质二级结构
  19. C++ 纯WIN32 API编程 悦读器实战示例
  20. 3.1 TMO MATLAB 框架(Advanced High Dynamic Range Imaging )

热门文章

  1. 人工智能第2章 智能 Agent
  2. 2022-2027年中国煤制尿素行业市场全景评估及发展战略规划报告
  3. 图像彩色化方法(深度学习)
  4. [vSphere]关闭ESXi特定警报
  5. /opt/MegaRAID/MegaCli/MegaCli64
  6. APM 新版电机电调校准
  7. 真Unity3d_人物摇杆操作(2022年重写)
  8. CSS预处理之less,sass
  9. 计算机设计大赛志愿服务活动,中国大学生计算机设计大赛 | 志愿者招募
  10. 【STM32技巧】ADC模拟量采集的几种用法