Double Taxation when using a RelativeLayout on Android -


in order understand double taxation on android, wrote following code pretty simple. there relativelayout 3 textviews.

<?xml version="1.0" encoding="utf-8"?> <ru.maksim.sample_app.myrelativelayout 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="ru.maksim.sample_app.mainactivity">      <ru.maksim.sample_app.mytextview         android:id="@+id/text1"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:background="#fca"         android:tag="text1"         android:text="text 1" />      <ru.maksim.sample_app.mytextview         android:id="@+id/text2"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_below="@id/text1"         android:background="#acf"         android:tag="text2"         android:text="text 2" />      <ru.maksim.sample_app.mytextview         android:id="@+id/text3"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_below="@id/text1"         android:layout_torightof="@id/text2"         android:background="#fac"         android:tag="text3"         android:text="text 3" />  </ru.maksim.sample_app.myrelativelayout> 

mytextview

public class mytextview extends android.support.v7.widget.appcompattextview {      private static final string tag = "mytextview";      public mytextview(context context) {         super(context);     }      public mytextview(context context,                       @nullable attributeset attrs     ) {         super(context, attrs);     }      public mytextview(context context, @nullable attributeset attrs, int defstyleattr) {         super(context, attrs, defstyleattr);     }      @override     protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {         super.onmeasure(widthmeasurespec, heightmeasurespec);         int widthmode = view.measurespec.getmode(widthmeasurespec);         int heightmode = view.measurespec.getmode(heightmeasurespec);         log.d(tag,               "onmeasure, "                       + gettag()                       + " widthmeasurespec=" + measurespecmap.getname(widthmode)                       + " heightmeasurespec=" + measurespecmap.getname(heightmode)         );     }      @override     protected void onlayout(boolean changed, int left, int top, int right, int bottom) {         super.onlayout(changed, left, top, right, bottom);         log.d(tag, gettag() + " onlayout");     } } 

myrelativelayout

public class myrelativelayout extends relativelayout {      public static final string tag = "myrelativelayout";      public myrelativelayout(context context) {         super(context);     }      public myrelativelayout(context context, attributeset attrs) {         super(context, attrs);     }      public myrelativelayout(context context, attributeset attrs, int defstyleattr) {         super(context, attrs, defstyleattr);     }      @override     protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {         super.onmeasure(widthmeasurespec, heightmeasurespec);         int widthmode = view.measurespec.getmode(widthmeasurespec);         int heightmode = view.measurespec.getmode(heightmeasurespec);         log.d(tag,               "onmeasure, "                       + gettag()                       + " widthmeasurespec=" + measurespecmap.getname(widthmode)                       + " heightmeasurespec=" + measurespecmap.getname(heightmode)         );     }      @override     protected void onlayout(boolean changed, int left, int top, int right, int bottom) {         super.onlayout(changed, left, top, right, bottom);         log.d(tag, gettag() + " onlayout");     } } 

logcat:

09-11 19:25:40.077 7732-7732/ru.maksim.sample_app d/mytextview: onmeasure, text2 widthmeasurespec=at_most heightmeasurespec=at_most 09-11 19:25:40.078 7732-7732/ru.maksim.sample_app d/mytextview: onmeasure, text3 widthmeasurespec=at_most heightmeasurespec=at_most 09-11 19:25:40.078 7732-7732/ru.maksim.sample_app d/mytextview: onmeasure, text1 widthmeasurespec=exactly heightmeasurespec=at_most 09-11 19:25:40.078 7732-7732/ru.maksim.sample_app d/mytextview: onmeasure, text1 widthmeasurespec=exactly heightmeasurespec=at_most 09-11 19:25:40.078 7732-7732/ru.maksim.sample_app d/mytextview: onmeasure, text3 widthmeasurespec=exactly heightmeasurespec=at_most 09-11 19:25:40.078 7732-7732/ru.maksim.sample_app d/mytextview: onmeasure, text2 widthmeasurespec=exactly heightmeasurespec=at_most 09-11 19:25:40.078 7732-7732/ru.maksim.sample_app d/myrelativelayout: onmeasure, null widthmeasurespec=exactly heightmeasurespec=exactly                                                                        [ 09-11 19:25:40.098  7732: 7748 d/         ]                                                                       hostconnection::get() new host connection established 0xa0a8fbc0, tid 7748 09-11 19:25:40.132 7732-7732/ru.maksim.sample_app d/mytextview: onmeasure, text2 widthmeasurespec=at_most heightmeasurespec=at_most 09-11 19:25:40.132 7732-7732/ru.maksim.sample_app d/mytextview: onmeasure, text3 widthmeasurespec=at_most heightmeasurespec=at_most 09-11 19:25:40.132 7732-7732/ru.maksim.sample_app d/mytextview: onmeasure, text1 widthmeasurespec=exactly heightmeasurespec=at_most 09-11 19:25:40.132 7732-7732/ru.maksim.sample_app d/mytextview: onmeasure, text1 widthmeasurespec=exactly heightmeasurespec=at_most 09-11 19:25:40.132 7732-7732/ru.maksim.sample_app d/mytextview: onmeasure, text3 widthmeasurespec=exactly heightmeasurespec=at_most 09-11 19:25:40.132 7732-7732/ru.maksim.sample_app d/mytextview: onmeasure, text2 widthmeasurespec=exactly heightmeasurespec=at_most 09-11 19:25:40.132 7732-7732/ru.maksim.sample_app d/myrelativelayout: onmeasure, null widthmeasurespec=exactly heightmeasurespec=exactly 09-11 19:25:40.132 7732-7732/ru.maksim.sample_app d/mytextview: text1 onlayout 09-11 19:25:40.132 7732-7732/ru.maksim.sample_app d/mytextview: text2 onlayout 09-11 19:25:40.132 7732-7732/ru.maksim.sample_app d/mytextview: text3 onlayout 09-11 19:25:40.132 7732-7732/ru.maksim.sample_app d/myrelativelayout: null onlayout 

now let's replace myrelativelayout child of linearlayoiut called mylinearlayout:

<?xml version="1.0" encoding="utf-8"?> <ru.maksim.sample_app.mylinearlayout 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"     android:orientation="vertical"     tools:context="ru.maksim.sample_app.mainactivity">      <ru.maksim.sample_app.mytextview         android:id="@+id/text1"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:background="#fca"         android:tag="text1"         android:text="text 1" />      <ru.maksim.sample_app.mytextview         android:id="@+id/text2"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:background="#acf"         android:tag="text2"         android:text="text 2" />      <ru.maksim.sample_app.mytextview         android:id="@+id/text3"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:background="#fac"         android:tag="text3"         android:text="text 3" />  </ru.maksim.sample_app.mylinearlayout> 

mylinearlayout

public class mylinearlayout extends linearlayout {      public static final string tag = "mylinearlayout";      public mylinearlayout(context context) {         super(context);     }      public mylinearlayout(context context, attributeset attrs) {         super(context, attrs);     }      public mylinearlayout(context context, attributeset attrs, int defstyleattr) {         super(context, attrs, defstyleattr);     }      @override     protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {         super.onmeasure(widthmeasurespec, heightmeasurespec);         int widthmode = view.measurespec.getmode(widthmeasurespec);         int heightmode = view.measurespec.getmode(heightmeasurespec);         log.d(tag,               "onmeasure, "                       + gettag()                       + " widthmeasurespec=" + measurespecmap.getname(widthmode)                       + " heightmeasurespec=" + measurespecmap.getname(heightmode)         );     }      @override     protected void onlayout(boolean changed, int left, int top, int right, int bottom) {         super.onlayout(changed, left, top, right, bottom);         log.d(tag, gettag() + " onlayout");     } } 

here see in logcat now:

09-11 19:50:57.974 2781-2781/? d/mytextview: onmeasure, text1 widthmeasurespec=exactly heightmeasurespec=at_most 09-11 19:50:57.974 2781-2781/? d/mytextview: onmeasure, text2 widthmeasurespec=at_most heightmeasurespec=at_most 09-11 19:50:57.974 2781-2781/? d/mytextview: onmeasure, text3 widthmeasurespec=exactly heightmeasurespec=at_most 09-11 19:50:57.974 2781-2781/? d/mylinearlayout: onmeasure, null widthmeasurespec=exactly heightmeasurespec=exactly                                                   [ 09-11 19:50:58.004  2781: 2817 d/         ]                                                  hostconnection::get() new host connection established 0xa5ec1940, tid 2817 09-11 19:50:58.017 2781-2781/? d/mytextview: onmeasure, text1 widthmeasurespec=exactly heightmeasurespec=at_most 09-11 19:50:58.017 2781-2781/? d/mytextview: onmeasure, text2 widthmeasurespec=at_most heightmeasurespec=at_most 09-11 19:50:58.017 2781-2781/? d/mytextview: onmeasure, text3 widthmeasurespec=exactly heightmeasurespec=at_most 09-11 19:50:58.017 2781-2781/? d/mylinearlayout: onmeasure, null widthmeasurespec=exactly heightmeasurespec=exactly 09-11 19:50:58.017 2781-2781/? d/mytextview: text1 onlayout 09-11 19:50:58.017 2781-2781/? d/mytextview: text2 onlayout 09-11 19:50:58.017 2781-2781/? d/mytextview: text3 onlayout 09-11 19:50:58.017 2781-2781/? d/mylinearlayout: null onlayout 

measurespecmap used in both examples above contains following map:

public class measurespecmap {      private static final map<integer, string> map = new hashmap<>();      static {         map.put(view.measurespec.at_most, "at_most");         map.put(view.measurespec.exactly, "exactly");         map.put(view.measurespec.unspecified, "unspecified");     }      private measurespecmap() {      }      public static string getname(int mode) {         return map.get(mode);     }  } 

question 1.

when using myrelativelayout, why system need call onmeasure on each child twice before onmeasure of myrelativelayout called? mylinearlayout each child in example measured once can see in log output above.

question 2.

here else the double taxation section don't understand:

when use relativelayout container, allows position view objects respect positions of other view objects, framework performs following actions:

executes layout-and-measure pass, during framework calculates each child object’s position , size, based on each child’s request. uses data, taking object weights account, figure out proper position of correlated views.

uses data, taking object weights account, figure out proper position of correlated views.

but wait... aren't talking android:layout_weight feature of linearlayout?


the code above available on github:

the approach mylinearlayout

the approach myrelativelayout

question 1.

when using myrelativelayout, why system need call onmeasure on each child twice before onmeasure of myrelativelayout called? mylinearlayout each child in example measured once can see in log output above.

in (overly) simple terms, comes down fact size , position of 1 view can affect size , position of view.

consider text3: width depends not on length of text holding, on width of text2; if text2 consumes 80% of screen, text3 (at most) 20% of screen.

so system first measure pass figure out "constraints" views going place on each other, , second measure pass figure out final values use.

take @ log output (some text omitted brevity):

d/mytextview: onmeasure, text2 widthmeasurespec=at_most heightmeasurespec=at_most d/mytextview: onmeasure, text3 widthmeasurespec=at_most heightmeasurespec=at_most d/mytextview: onmeasure, text1 widthmeasurespec=exactly heightmeasurespec=at_most  d/mytextview: onmeasure, text1 widthmeasurespec=exactly heightmeasurespec=at_most d/mytextview: onmeasure, text3 widthmeasurespec=exactly heightmeasurespec=at_most d/mytextview: onmeasure, text2 widthmeasurespec=exactly heightmeasurespec=at_most 

see how first time text2 measured, widthmeasurespec of mode at_most while second time of mode exactly? first pass giving text2 opportunity consume 100% of screen width, second pass limiting actual necessary size.

whereas vertical linearlayout, system can needs know in single measurement pass. text1 allowed full window height, text2 allowed full window height minus text1's height, , on.

question 2.

...

but wait... aren't talking android:layout_weight feature of linearlayout?

i don't understand part either. i'm inclined believe commonsware's speculation it's documentation bug.


Comments

Popular posts from this blog

angular - Ionic slides - dynamically add slides before and after -

minify - Minimizing css files -

Add a dynamic header in angular 2 http provider -