Android相关(3)
需要自定义一个组件CascadeLayout,让子view可以像拿扑克牌那样的层叠起来,主要实现效果:
& & & & & & & & & & & & & & & & & & & & & & & & & & &
为了设置子view之前的偏移距离,这里需要定义子view相对于上一张卡片的的左边距,上边距。然后每张卡片也可以单独的设置自己需要的边距。这个边距和不是指的内边距(padding)和外边距(margin),而是两张卡片之间的偏移距离。
在attrs中定义属性:
&?xml version=&1.0& encoding=&utf-8&?&
&resources&
&declare-styleable name=&Cascade_LayoutParams&&
&attr name=&layout_leftCardPadding& format=&dimension& /&
&attr name=&layout_topCardPadding& format=&dimension& /&
&/declare-styleable&
&declare-styleable name=&Cascade&&
&attr name=&leftCardPadding& format=&dimension& /&
&attr name=&topCardPadding& format=&dimension& /&
&/declare-styleable&
&/resources&
其中,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);
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,//相对于father的位置
int layoutLeftCardP//自己需要显示的左边的尺寸
int layoutTopCardP//自己需要显示的上边的尺寸
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray ta = c.obtainStyledAttributes(attrs, R.styleable.Cascade_LayoutParams);
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设置的值。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getPaddingLeft(), height = getPaddingTop();
int count = getChildCount();
for (int i = 0; i & i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
LayoutParams params = (LayoutParams) child.getLayoutParams();
//计算下一张card的左边距和上边距
int cardPaddingLeft = params.layoutLeftCardPadding & 0 ? params.layoutLeftCardPadding : leftCardP
int cardPaddingTop = params.layoutTopCardPadding & 0 ? params.layoutTopCardPadding : topCardP
//保存子view的位置
params.x =
params.y =
//累加的width和height
if (i != count - 1) {
width += cardPaddingL
height += cardPaddingT
} 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()了:
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
for (int i = 0; i & 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 需要重写以下方法
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof CascadeLayout.LayoutP
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
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);
测试使用的布局文件:
&?xml version=&1.0& encoding=&utf-8&?&
&LinearLayout xmlns:android=&/apk/res/android&
xmlns:phy=&/apk/res-auto&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:orientation=&vertical&&
&phy.cascade.CascadeLayout
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& /&
&/phy.cascade.CascadeLayout&
&/LinearLayout&
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:881次
排名:千里之外1、打开微信,扫一扫 2、 扫描上面二维码3、或者添加微信号:www-dzpk-com
您现在的位置: >
Andrew Brokos教你打扑克:如何做出正确的下注决策
虽然已经在领域认真玩牌十多年,但始终让我着迷的一点在于,它能让你在最常见的牌局中找到自身提高的空间。就拿翻牌前加注来说,这几乎是每一手牌里我都会要面临的决策,但当自己真正与对手抗衡时,我还是会在做最小加注、底池大小的加注,还是介于两者之间的加注这些问题上犹豫不决。虽然我有着无数个翻牌下注决策的经历,但在碰见这些常见的问题时,我依然会反复思考自己打法的正确性。我认为这种温故知新的扑克学习态度是很好的,只有在微小细节中不断磨练才能让自己的扑克技术有更深层的进步。下面我们就通过几个牌局来探讨一下究竟如何才是正确的下注决策。
首先我们先来了解一下,牌局中下注究竟能实现什么呢?大家要知道,当你进行下注(或加注)时,对手会有两种反应。他可以弃牌,也可以往底池投更多钱。正因为如此,你只有在能实现这两个目的中其中之一时才应该去下注,而最有利可图的下注就是能同时达到这两个目的。
下面来看一个例子,你手持6&5&在翻牌面:9&8&3&下注半诈唬对手。由于你拿着6高牌,目的肯定是想让对手弃牌,因为在这个牌面有重大的赢率。当然,你用任何弱牌下注也是想要达到这个目的。而这手牌的特别之处就在于,虽然对手继续往底池投钱时它无法受益,但你得到的伤害没有其他弱牌那么严重。在许多情况下,用听牌下注是有利可图的,但用其他弱牌下注则不是。
再来看看,假如你用A&9&在相同的翻牌圈是:9&8&3&下注。这时,你拿到了顶对带顶跟张,即使对手跟注你也有机会领先。对手极有可能拿着某种听牌,更低的对子,或者拿着顶对但被你压制的跟张。不过从另一个角度看,你的手牌很是脆弱的,虽然对手拿着KQ这样的牌会对下注弃牌,但如果能让他再多看两张牌的话,也有近25%的机会获胜。可如果对手拿着9 9或Q&9&,下注就变得没那么好了,因为对手十分有机会拿下这个彩池。
以上的例子都是相当基本的知识,但我希望大家能记住,因为我们接下来要来看一个更复杂的牌局。这是我参加$2,000春季线上扑克锦标赛中的一手牌。
当时盲注为50/100,底注10。我拿到了强牌A&A&,我率先行动,加注到300。一位技术精湛的锦标赛玩家在CO位跟注,其他人弃牌。底池里有840。对手大约还剩1万,我的筹码则有1.3万左右。翻牌为7&4&3&。我有一张A&,假如在这里下注而对手弃牌的话我将一无所获。因为转牌很可能出现第三张同花牌或第四张顺子牌。对手不可能在转牌拿到比我更大的对子,我手里的A&限制了对手拿到的同花听牌的几率,即使他在转牌拿到同花我也有再次听牌打败他的机会。
在这手牌中,很多时候对手可能拿着的任何顺子听牌来抵抗我,这是事实。例如他有7&6&的话,对抗我的A A就有超过30%的赢率。如果我能让对手弃掉这手牌就是极好的,但没理由相信一次下注能达到这个效果。当然,下注然后让对手拿着只有30%赢率的牌跟注会比让他免费看牌更好,而且许多会跟注你的牌赢率并不到30%。许多玩家或许没有注意这一点,他们下意识的想法是:&我有好牌,更差的牌会跟注我,该下注啦。&
我们回过头来仔细想想这一手牌。如果你的下注被加注的话,你会有什么应对?你愿意对多少转牌再次下注?愿意对多少河牌下注呢?如果你两次下注,然后在河牌过牌,如果对手做了大的下注,你会什么如何应多?
以上这些大家应该要都考虑到的,假如我的手牌是高对以及不带梅花的A A,我就会下注更小。因为我想让对手掉入陷阱,他要是弃牌的话是个好结果,如果跟注的话我也是可以接受。我并不是说下注然后被跟注对AA不好,我想说的是这看起来并没有那么好,所以其他选择更值得考虑。如果你过牌,对手可能会用许多原本要跟注你的牌下注,甚至还会用原本不会跟注甚至更弱的牌下注。如果翻牌圈都过牌,你就可以先发制人在转牌和河牌价值下注,并且更加相信你是领先对手的。所以通过以上分析我最终选择过牌。对手下注半个底池,我跟注。转牌为7&,我过牌,他再次下注半个底池,我跟注。河牌为7&,我过牌,他下注三分之二的底池,我再次跟注,击败了他的口袋5。
下面我们来看看对手的下注决策。我认为他决策都执行的很好,就是结果不尽人意。
我在翻牌圈过牌后,他的牌是很有机会成为最好的牌,但在这样的牌面,我不仅能轻松成为强对子,而且只要假装自己完成强对子,对手就会进入两难的境地。因此,他的55很难获取价值。
同时,分析对手心理,他认为即使被跟注,55也不差。它们仍领先AK,对抗更高的对子(除了6 6)还有6张补牌,而且还有假装暗三或顺子的可能性。在转牌圈也是同样的道理。他不会去考虑转牌提高击败自己牌的概率,他仍能从防御高牌中获利。同样的,他也能从我的弃牌中获利,就算我跟注,他的情况也不差。可是在我跟注两次下注后,我击败5 5的概率大幅提升。在这样的牌面,对手大部分想法会选择放弃,有一点摊牌价值都行,但这张河牌7&给了他一个假装成强牌的机会。实际上我已经拿着非常重要的阻隔牌,在河牌轻松跟注。到这里大家可以看出,我在翻牌过牌时,所有计划的就按部就班的进行着。但我仍认为对手打得很好。他只是运气不好,三次开火诈唬的范围刚好撞上了我跟注到底的范围。
或许很多人会说,宁愿在翻牌下注,避免在河牌用抓诈唬牌跟注大的下注的情况出现。可惜,当你面对一位技术超群玩家,而你自己又没有位置优势时,你总会没法避免做艰难抉择的。所以最好应对方式就是抢占先机,做好准备。如果我在翻牌下注的话,对手加注,这会让我很难办。他可能会跟注,然后在转牌对我的下注加注,或对我的过牌下注,又或者跟注然后对我河牌的下注加注,也有可能对我的河牌的过牌下注等等。重点是,我无法阻止他假装有大牌,所以宁愿在对手真的有大牌时,让自己能做一个清晰的决策。不过,我手里拿着A&的话,让对手跟注比大范围的弃牌更有利可图,这同时也意味着我得到的信息量更多。
这手丰富行动的牌局来自高级别锦标赛,这种锦标赛里充满了三条街下注、大的诈唬、大的跟注以及大家不是每天都能看到的东西。不过我最后想说的是,最重要的决策通常会发生在微小操作中。正所谓细节决定成败,我必须认真考虑是否在翻牌继续下注,然后对手在面对我的过牌时是否下注。相信通过我分析这些关键点,能为大家展示基础知识的重要性,同时为大家在今后扑克技巧上提供一些帮助和指导作用。在明天,小编还会为大家继续带来Andrew Brokos教你打扑克的系列文章,精彩内容不要错过!
声明: ()内所有内容并不反映任何中扑网之意见及观点,文章转载请注明出处及源链接。更多德州扑克资讯资源请继续关注中扑网同时也欢迎您关注中扑网官网微博: ,转载请注明出处及源链接。
1、打开微信,扫一扫2、扫描右边二维码3、或者添加微信号:www-dzpk-com
发送给朋友
分享到朋友圈
推荐俱乐部
作者:Will Tipton
优惠价:¥
原价:¥150
作者:Doug Hull
优惠价:¥
原价:¥150
作者:Chr is Moorman
优惠价:¥
原价:¥150