android - Top margin is substracted from height in API10 and below -
in project i'm working on, i'm positioning views within framelayout
wrap_content
:
<framelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".mainactivity"> <framelayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#ff0400"> <textview android:background="#04ff00" android:text="test" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_margintop="10dp" android:layout_marginleft="10dp" android:layout_marginbottom="10dp" android:layout_gravity="top|left" /> </framelayout> </framelayout>
since android 3.0 (api11) rendered layout expected:
but in android 2.3.3 (api10) , below, marginbottom
of green textview
seems extracted red framelayout
:
why layout not rendered expected in api10 , below? bug in android? if so, there quick workaround?
i know apply bottom padding framelayout
instead of bottom margin textview
. in case have no easy way achieve this, since layouts built programmatically.
edit (22-07)
during quest find out fixed issue, looked @ the changes between api10 , api11. can't find chances in framelayout
class. weird because following bug (which think might related) fixed in api11: https://code.google.com/p/android/issues/detail?id=28057.
edit (23-07)
the margin bottom doesn't seem problem; removing doesn't make difference. seems top margin causes wrong height in api10 , below.
the framelayout
documentation states following:
framelayout designed block out area on screen display single item. generally, framelayout should used hold single child view, because can difficult organize child views in way that's scalable different screen sizes without children overlapping each other.
this reason me drop framelayout
.
then started searching different viewgroup
supports positioning elements x / y , ability provide gravity.
the absolutelayout
supports positioning x / y (and deprecated).
the relativelayout
measuring (in case) means bad performance.
so ended creating own viewgroup
, merge of framelayout
's gravity, , absolutelayout
's x/y:
package com.example.common.widget; import java.util.arraylist; import android.content.context; import android.content.res.typedarray; import android.util.attributeset; import android.view.gravity; import android.view.view; import android.view.viewgroup; public class fixedlayout extends viewgroup { private static final int default_child_gravity = gravity.top; private final arraylist<view> mmatchparentchildren = new arraylist<view>(); public fixedlayout(context context) { super(context); } public fixedlayout(context context, attributeset attrs) { super(context, attrs); } public fixedlayout(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { int count = getchildcount(); final boolean measurematchparentchildren = measurespec.getmode(widthmeasurespec) != measurespec.exactly || measurespec.getmode(heightmeasurespec) != measurespec.exactly; mmatchparentchildren.clear(); int maxheight = 0; int maxwidth = 0; int childstate = 0; // find rightmost , bottom-most child (int = 0; < count; i++) { view child = getchildat(i); if (child.getvisibility() != gone) { measurechildwithmargins(child, widthmeasurespec, 0, heightmeasurespec, 0); final layoutparams lp = (layoutparams)child.getlayoutparams(); maxwidth = math.max(maxwidth, child.getmeasuredwidth() + lp.leftmargin + lp.rightmargin); maxheight = math.max(maxheight, child.getmeasuredheight() + lp.topmargin + lp.bottommargin); childstate = childstate | getchildmeasuredstate(child); if (measurematchparentchildren) { if (lp.width == layoutparams.match_parent || lp.height == layoutparams.match_parent) { mmatchparentchildren.add(child); } } } } // account padding maxwidth += getpaddingleft() + getpaddingright(); maxheight += getpaddingtop() + getpaddingbottom(); // check against minimum height , width maxheight = math.max(maxheight, getsuggestedminimumheight()); maxwidth = math.max(maxwidth, getsuggestedminimumwidth()); setmeasureddimension( getresolvedsizeandstate(maxwidth, widthmeasurespec, childstate), getresolvedsizeandstate(maxheight, heightmeasurespec, childstate << measured_height_state_shift)); (int = 0; < mmatchparentchildren.size(); i++) { final view child = mmatchparentchildren.get(i); final layoutparams lp = (layoutparams)child.getlayoutparams(); int childwidthmeasurespec; int childheightmeasurespec; if (lp.width == layoutparams.match_parent) { childwidthmeasurespec = measurespec.makemeasurespec(getmeasuredwidth() - getpaddingleft() - getpaddingright() - lp.leftmargin - lp.rightmargin - lp.x, measurespec.exactly); } else { childwidthmeasurespec = getchildmeasurespec(widthmeasurespec, getpaddingleft() + getpaddingright() + lp.leftmargin + lp.rightmargin + lp.x, lp.width); } if (lp.height == layoutparams.match_parent) { childheightmeasurespec = measurespec.makemeasurespec(getmeasuredheight() - getpaddingtop() - getpaddingbottom() - lp.topmargin - lp.bottommargin - lp.y, measurespec.exactly); } else { childheightmeasurespec = getchildmeasurespec(heightmeasurespec, getpaddingtop() + getpaddingbottom() + lp.topmargin + lp.bottommargin + lp.y, lp.height); } child.measure(childwidthmeasurespec, childheightmeasurespec); } } /** * returns set of layout parameters width of * {@link android.view.viewgroup.layoutparams#wrap_content}, height of * {@link android.view.viewgroup.layoutparams#wrap_content} , coordinates (0, 0). */ @override protected viewgroup.layoutparams generatedefaultlayoutparams() { return new layoutparams(layoutparams.wrap_content, layoutparams.wrap_content, 0, 0); } /** * ask 1 of children of view measure itself, taking account both * measurespec requirements view , padding , margins. child must have * marginlayoutparams heavy lifting done in getchildmeasurespec. * * @param child * child measure * @param parentwidthmeasurespec * width requirements view * @param widthused * space has been used parent horizontally (possibly other * children of parent) * @param parentheightmeasurespec * height requirements view * @param heightused * space has been used parent vertically (possibly other * children of parent) */ @override protected void measurechildwithmargins(view child, int parentwidthmeasurespec, int widthused, int parentheightmeasurespec, int heightused) { final layoutparams lp = (layoutparams)child.getlayoutparams(); final int childwidthmeasurespec = getchildmeasurespec(parentwidthmeasurespec, getpaddingleft() + getpaddingright() + lp.leftmargin + lp.rightmargin + lp.x + widthused, lp.width); final int childheightmeasurespec = getchildmeasurespec(parentheightmeasurespec, getpaddingtop() + getpaddingbottom() + lp.topmargin + lp.bottommargin + lp.y + heightused, lp.height); child.measure(childwidthmeasurespec, childheightmeasurespec); } @override protected void onlayout(boolean changed, int left, int top, int right, int bottom) { int count = getchildcount(); final int parentleft = getpaddingleft(); final int parentright = right - left - getpaddingright(); final int parenttop = getpaddingtop(); final int parentbottom = bottom - top - getpaddingbottom(); (int = 0; < count; i++) { view child = getchildat(i); if (child.getvisibility() != gone) { final layoutparams lp = (layoutparams)child.getlayoutparams(); final int width = child.getmeasuredwidth(); final int height = child.getmeasuredheight(); int childleft; int childtop; int gravity = lp.gravity; if (gravity == -1) { gravity = default_child_gravity; } final int horizontalgravity = gravity & gravity.horizontal_gravity_mask; final int verticalgravity = gravity & gravity.vertical_gravity_mask; switch (horizontalgravity) { case gravity.left: childleft = parentleft + lp.x; break; case gravity.center_horizontal: childleft = parentleft + (parentright - parentleft - width) / 2 + lp.x; break; case gravity.right: childleft = parentright - width - lp.x; break; default: childleft = parentleft + lp.x; } switch (verticalgravity) { case gravity.top: childtop = parenttop + lp.y; break; case gravity.center_vertical: childtop = parenttop + (parentbottom - parenttop - height) / 2 + lp.y; break; case gravity.bottom: childtop = parentbottom - height - lp.y; break; default: childtop = parenttop + lp.y; } child.layout(childleft, childtop, childleft + width, childtop + height); } } } @override public viewgroup.layoutparams generatelayoutparams(attributeset attrs) { return new fixedlayout.layoutparams(getcontext(), attrs); } // override allow type-checking of layoutparams. @override protected boolean checklayoutparams(viewgroup.layoutparams p) { return p instanceof fixedlayout.layoutparams; } @override protected viewgroup.layoutparams generatelayoutparams(viewgroup.layoutparams p) { return new layoutparams(p); } @override public boolean shoulddelaychildpressedstate() { return false; } /** * return state bits of {@link #getmeasuredwidthandstate()} , * {@link #getmeasuredheightandstate()} of child view, combined 1 integer. width * component in regular bits {@link #measured_state_mask} , height component @ * shifted bits {@link #measured_height_state_shift}>>{@link #measured_state_mask}. */ public final int getchildmeasuredstate(view child) { return (child.getmeasuredwidth() & measured_state_mask) | ((child.getmeasuredheight() >> measured_height_state_shift) & (measured_state_mask >> measured_height_state_shift)); } /** * utility reconcile desired size , state, constraints imposed measurespec. * take desired size, unless different size imposed constraints. * returned value compound integer, resolved size in * {@link #measured_size_mask} bits , optionally bit {@link #measured_state_too_small} set * if resulting size smaller size view wants be. * * @param size * how big view wants * @param measurespec * constraints imposed parent * @return size information bit mask defined {@link #measured_size_mask} , * {@link #measured_state_too_small}. */ public static int getresolvedsizeandstate(int size, int measurespec, int childmeasuredstate) { int result = size; int specmode = measurespec.getmode(measurespec); int specsize = measurespec.getsize(measurespec); switch (specmode) { case measurespec.unspecified: result = size; break; case measurespec.at_most: if (specsize < size) { result = specsize | measured_state_too_small; } else { result = size; } break; case measurespec.exactly: result = specsize; break; } return result | (childmeasuredstate & measured_state_mask); } /** * per-child layout information associated absolutelayout. see * {@link android.r.styleable#absolutelayout_layout absolute layout attributes} list of * child view attributes class supports. */ public static class layoutparams extends viewgroup.marginlayoutparams { /** * horizontal, or x, location of child within view group. */ public int x; /** * vertical, or y, location of child within view group. */ public int y; /** * gravity apply view these layout parameters associated. * * @see android.view.gravity */ public int gravity = -1; /** * creates new set of layout parameters specified width, height , location. * * @param width * width, either {@link #match_parent}, {@link #wrap_content} or fixed size * in pixels * @param height * height, either {@link #match_parent}, {@link #wrap_content} or fixed * size in pixels */ public layoutparams(int width, int height) { super(width, height); } /** * creates new set of layout parameters specified width, height , location. * * @param width * width, either {@link #match_parent}, {@link #wrap_content} or fixed size * in pixels * @param height * height, either {@link #match_parent}, {@link #wrap_content} or fixed * size in pixels * @param x * x location of child * @param y * y location of child */ public layoutparams(int width, int height, int x, int y) { super(width, height); this.x = x; this.y = y; } /** * creates new set of layout parameters. values extracted supplied * attributes set , context. xml attributes mapped set of layout parameters * are: * * <ul> * <li><code>layout_x</code>: x location of child</li> * <li><code>layout_y</code>: y location of child</li> * <li>all xml attributes {@link android.view.viewgroup.layoutparams}</li> * </ul> * * @param c * application environment * @param attrs * set of attributes extract layout parameters values */ public layoutparams(context c, attributeset attrs) { super(c, attrs); typedarray = c.obtainstyledattributes(attrs, com.example.common.r.styleable.fixedlayout_layout); gravity = a.getint(com.example.common.r.styleable.fixedlayout_layout_layout_gravity, -1); x = a.getdimensionpixeloffset( com.example.common.r.styleable.fixedlayout_layout_layout_x, 0); y = a.getdimensionpixeloffset( com.example.common.r.styleable.fixedlayout_layout_layout_y, 0); topmargin = a.getdimensionpixeloffset( com.example.common.r.styleable.fixedlayout_layout_layout_margintop, 0); leftmargin = a.getdimensionpixeloffset( com.example.common.r.styleable.fixedlayout_layout_layout_marginleft, 0); bottommargin = a.getdimensionpixeloffset( com.example.common.r.styleable.fixedlayout_layout_layout_marginbottom, 0); rightmargin = a.getdimensionpixeloffset( com.example.common.r.styleable.fixedlayout_layout_layout_marginright, 0); a.recycle(); } /** * {@inheritdoc} */ public layoutparams(viewgroup.layoutparams source) { super(source); } } }
Comments
Post a Comment