Android扑克牌抽奖View,android自定义层级view,扑克牌堆叠效果,cascadeLayout
需要自定义一个组件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相关推荐
- Android签名背景颜色,Android UI设计系列之自定义DrawView组件实现数字签名效果(5)...
最近项目中有个新的需求,用户在完交易需要进行输入支付密码付款的时候,要让用户签下自己的签名,提起到数字签名这个东西,感觉有点高大上,后来想想数字签名的原理也不是太复杂,主要实现原理就是利用了View的 ...
- Android基础控件——ProgressBar自定义的介绍、动画效果实现、附加三个漂亮的进度条
ProgressBar自定义的介绍.动画效果实现.附加三个漂亮的进度条 shape属性介绍: corners 圆角 gradient 渐变 padding 内容离边界距离 size 大小 ...
- android的三个基础控件,Android基础控件——ProgressBar自定义的介绍、动画效果实现、附加三个漂亮的进度条...
xml文件: android:centerColor="#00ff00" android:endColor="#0000ff" android:startCol ...
- Android:手把手教你自定义头像View,可根据名字自动生成背景色+文字的显示效果,含动画效果。
首先看需要做成的效果,如下所示
- android layout include merge,Android 布局优化之include与merge
Android 官方提供了三个用来优化布局的标签,分别是include.merge与ViewStub,其中ViewStub是动态加载视图到内存,大家可以查阅:Android UI布局优化之ViewSt ...
- android录制mp3音频,Android MP3录制,波形显示,音频权限兼容与播放
我又来掀桌子了(ノಠ益ಠ)ノ彡┻━┻,这次是MP3录制和显示声音波形的一个故事. 先看看效果┑( ̄Д  ̄)┍ 2 1 MP3录制的逻辑过程就忽略了(真的不是因为懒(.・・)ノ),这里用的是开源的And ...
- android sqlite自定义函数,Android中自定义一个View的方法详解
本文实例讲述了Android中自定义一个View的方法.分享给大家供大家参考,具体如下: Android中自定义View的实现比较简单,无非就是继承父类,然后重载方法,即便如此,在实际编码中难免会遇到 ...
- android minheight的作用,Android 自定义 View 最少必要知识
1. 什么是自定义 View? 1.1 定义 在 Android 系统中,界面中所有能看到的元素都是 View.默认情况下,Android 系统为开发者提供了很多 View,比如用于展示文本信息的 T ...
- android炫酷的自定义view,Android自定义View实现炫酷进度条
本文实例为大家分享了Android实现炫酷进度条的具体代码,供大家参考,具体内容如下 下面我们来实现如下效果: 第一步:创建attrs文件夹,自定义属性: 第二步:自定义View: /** * Cre ...
最新文章
- 1020 Tree Traversals
- poj1364(差分约束+Bellman-ford)
- 每天一个linux命令(25):linux文件属性详解
- 洛谷 P1678 烦恼的高考志愿
- c语言字符串去重简单,C语言实现简单飞机大战
- 关于web爬虫的tips
- Magento微信支付接口开发小记
- 非root用户ssh 执行 sudo远程机器免密钥
- Wireshark 检索命令
- 如何隐藏所有的导航栏
- [python]练习之判断3个数值中最大值
- 高通IPQ4019 IPQ4029 模块+底板双频 AC无线路由模块开发板
- MSC-51单片机原理与实践——第四章习题及答案解析
- 浅谈企业网站建设注意事项
- 整理2020智能车竞赛网站各分赛区报名情况
- MacBookPro阻止电脑自动下载更新
- 中国设备工程杂志中国设备工程杂志社中国设备工程编辑部2022年第18期目录
- psi-pred安装及预测蛋白质二级结构
- C++ 纯WIN32 API编程 悦读器实战示例
- 3.1 TMO MATLAB 框架(Advanced High Dynamic Range Imaging )