8

I have android layout design in which I have an AppBar layout which will contain a Toolbar and one more LinearLayout design with circle Drawable as TextView. which is off same height. So when I try to get the Toolbar or AppBar height/width it's returning only 0.

activity_main.xml:

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="enterAlways" />
       <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:layout_gravity="center_horizontal"
            android:background="@color/colorPrimary"
            android:orientation="horizontal"
            app:layout_scrollFlags="enterAlways">

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/marked_questions"
                    style="@style/textview_summary_omr_toolbar_count"
                    android:background="@drawable/bg_percentage_default"
                    android:text="18" />

                <TextView
                    style="@style/textview_heading_summary_omr_toolbar"
                    android:text="Marked" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/correct"
                    style="@style/textview_summary_omr_toolbar_count"
                    android:background="@drawable/bg_percentage_6"
                    android:text="18"

                    />

                <TextView
                    style="@style/textview_heading_summary_omr_toolbar"
                    android:text="Correct" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/wrong"
                    style="@style/textview_summary_omr_toolbar_count"
                    android:background="@drawable/bg_percentage_wrong"
                    android:text="18" />

                <TextView
                    style="@style/textview_heading_summary_omr_toolbar"
                    android:text="Wrong" />
            </LinearLayout>


            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/conflicts"
                    style="@style/textview_summary_omr_toolbar_count"
                    android:background="@drawable/bg_percentage_3"
                    android:text="0" />

                <TextView
                    style="@style/textview_heading_summary_omr_toolbar"
                    android:text="Conflicts" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    style="@style/textview_summary_omr_toolbar_count"
                    android:text="Score:"
                    android:textColor="@android:color/white" />

                <TextView
                    android:id="@+id/marks_scored"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:gravity="center"
                    android:text="18/30"
                    android:textColor="@android:color/white"
                    android:textSize="18sp" />

            </LinearLayout>


        </LinearLayout>
    </android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>

MainActivity.java: Here I am initializing the Toolbar and AppBar and try to print the width and height of both in logs ,which is returning me zero.

public class MainActivity extends AppCompatActivity {
  private Toolbar toolbar;
  private AppBarLayout app_bar;
protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       app_bar = (AppBarLayout) findViewById(R.id.app_bar);
       toolbar = (Toolbar) findViewById(R.id.toolbar);
       logToolbarLayoutParams();

}
private void logToolbarLayoutParams() {
        Log.d(TAG,"Toolbar width/Height"+this.toolbar.getWidth()+"/"+this.toolbar.getHeight());
        Log.d(TAG,"App_bar width/height"+this.app_bar.getWidth()+"/"+this.app_bar.getHeight());

}

I have also referred to this question in the stackoverflow.

final AppBarLayout app_bar = (AppBarLayout) findViewById(R.id.app_bar);
                ViewTreeObserver vto = app_bar.getViewTreeObserver();
                vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        app_bar.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                        Log.d(TAG, "Global layout");
                        logToolbarLayoutParams();
            }
        });

If I add the following code in my MainActivity it's getting me the proper height and width of Toolbar. From the stackoverflow question which I mentioned before, I came to know that, the views were not drawn on the screen, so I have to wait. But my doubt here is, the design which i have specified is not a complex one? why its taking much time to draw on screen? am I missing something?

I have used Hierarchy Viewer to find out, what's making the child layout to load slowly. I found that I am using mulitple LinearLayout where single RelativeLayout can be used to obtain the same structure. I have changed my layout design as the following. Still I am facing the same issue.

updated: activity_main.xml:

<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="enterAlways" />
   <RelativeLayout
         android:id="@+id/summary_bottom_sheet"
         android:layout_width="match_parent"
         android:layout_height="?actionBarSize"
         android:layout_gravity="center_horizontal"
         android:background="@color/colorPrimary">


         <TextView
             android:id="@+id/marked_questions"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_alignParentLeft="true"
             android:layout_alignParentStart="true"
             android:background="@drawable/bg_percentage_default"
             android:text="18" />

         <TextView
             android:id="@+id/marked_textview"
             style="@style/textview_heading_summary_omr_toolbar"
             android:layout_toEndOf="@+id/marked_questions"
             android:layout_toRightOf="@+id/marked_questions"
             android:text="Marked" />


         <TextView
             android:id="@+id/correct"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_toEndOf="@+id/marked_textview"
             android:layout_toRightOf="@+id/marked_textview"
             android:background="@drawable/bg_percentage_6"
             android:text="18"

             />

         <TextView
             android:id="@+id/correct_textview"
             style="@style/textview_heading_summary_omr_toolbar"
             android:layout_toEndOf="@+id/correct"
             android:layout_toRightOf="@+id/correct"
             android:text="Correct" />


         <TextView
             android:id="@+id/wrong"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_toEndOf="@+id/correct_textview"
             android:layout_toRightOf="@+id/correct_textview"
             android:background="@drawable/bg_percentage_wrong"
             android:text="18" />

         <TextView
             android:id="@+id/wrong_textview"
             style="@style/textview_heading_summary_omr_toolbar"
             android:layout_toEndOf="@+id/wrong"
             android:layout_toRightOf="@+id/wrong"
             android:text="Wrong" />


         <TextView
             android:id="@+id/conflicts"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_toEndOf="@+id/wrong_textview"
             android:layout_toRightOf="@+id/wrong_textview"
             android:background="@drawable/bg_percentage_3"
             android:text="0" />

         <TextView
             android:id="@+id/conflicts_textview"
             style="@style/textview_heading_summary_omr_toolbar"
             android:layout_toEndOf="@+id/conflicts"
             android:layout_toRightOf="@+id/conflicts"
             android:text="Conflicts" />


         <TextView
             android:id="@+id/score_textview"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_toEndOf="@+id/conflicts_textview"
             android:layout_toRightOf="@+id/conflicts_textview"
             android:background="@null"
             android:gravity="center"
             android:text="Score:"
             android:textColor="@android:color/white" />

         <TextView
             android:id="@+id/marks_scored"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_centerVertical="true"
             android:layout_gravity="center_vertical"
             android:layout_toEndOf="@+id/score_textview"
             android:layout_toRightOf="@+id/score_textview"
             android:gravity="center"
             android:text="18/30"
             android:textColor="@android:color/white"
             android:textSize="18sp" />
   </RelativeLayout>
 </android.support.design.widget.AppBarLayout>
 </android.support.design.widget.CoordinatorLayout>

The following is the hierarchy viewer Hierarchy_viewer Image I am obtaining

Community
  • 1
  • 1
HourGlass
  • 1,805
  • 1
  • 15
  • 29
  • 1
    Use hierarchy viewer to test your layout for performance issues. https://developer.android.com/studio/profile/optimize-ui.html – Muhammad Babar Dec 06 '16 at 06:32
  • post your updated hierarchy viewer and your java code. becasue, it may not be your hierarchy issue. – Noorul Dec 08 '16 at 06:41
  • If you're just asking why you need to use an `OnGlobalLayoutListener`, it's because `View`s won't be laid out or drawn in `onCreate()`. That's just how it is. It's nothing to do with your particular layout, or how complex it is. – Mike M. Dec 08 '16 at 10:00
  • @MikeM. I am aware of that mike. But my question here is why it's taking more time. It's a simple design which have nothing but an app_bar, don't have too many match_parents(as you know if the child views have too many match_parent and wrap_content it will take more time to calculate views and draw the same on screen). why my design is forcing me to use globallayout listener is my question to be exact – HourGlass Dec 08 '16 at 10:21
  • And that's what I'm saying. It's not your particular design. You can't get any `View` dimensions in `onCreate()` because they won't be laid out yet. The `OnGlobalLayoutListener` is just a way to delay getting the dimensions until then. Change your layout to a simple, single `FrameLayout`, and test. It'll be the same thing. Both width and height will be 0 in `onCreate()`. It's not just your particular layout. – Mike M. Dec 08 '16 at 10:32
  • @MikeM. yes totally agree with . This doubt came on loading came on after using an imageview inside scrollview and i had an image to place on imageview. Before placing it I was trying to scale it down matching imageview width , as you know the childView were not loaded it gave me 0. and then i tried using GlobalLayout listener with Imageview as well scrollview.But I was unable to achieve, what i was trying. any advice on this.? – HourGlass Dec 08 '16 at 13:15
  • Dunno. Did you have `wrap_content` dimensions on the `ImageView`? If so, without an image in it, it would wrap to 0. – Mike M. Dec 08 '16 at 20:30
  • yes i have kept imageview to wrap_content. i have tried with and without imageview in both cases it's 0. @MikeM. – HourGlass Dec 09 '16 at 03:26
  • Then that `ImageView` is going to have 0 width/height until you put an image in it, even after everything is laid out (unless you have `fillViewport` set to `true` on the `ScrollView`, that is). – Mike M. Dec 09 '16 at 03:32
  • okay. I tried placing image to imageview as well. same result. – HourGlass Dec 09 '16 at 03:37
  • 1
    Then you're probably still not doing something quite right. I can't tell what that might be, though, from the vague description in comments. – Mike M. Dec 09 '16 at 04:03
  • Why don't you try calling `logToolbarLayoutParams();` from `onResume()` ? – MKJParekh Dec 13 '16 at 13:57
  • Try `ConstraintLayout`, it's in beta, but Android team promises it's faster – Dmytro Rostopira Dec 13 '16 at 14:48
  • Try to put the RelativeLayout containing all the TextViews inside the Toolbar. – Gordak Dec 13 '16 at 19:34
  • @Gordak tried the same. no good came out of it. – HourGlass Dec 14 '16 at 04:55
  • @DimaRostopira will give a try with constraintLayout – HourGlass Dec 14 '16 at 04:56
  • @MKJParekh , thought about it tried before, same result – HourGlass Dec 14 '16 at 04:59

5 Answers5

3

You're thinking about this wrong. There is nothing wrong with your layout (as it relates to your question). To prove it, completely change your layout and try again

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
    Log.d("SomeTag", "w: " + recyclerView.getWidth() + ", h: " + recyclerView.getHeight());
    Log.d("SomeTag", "mw: " + recyclerView.getMeasuredWidth() + ", mh: " + recyclerView.getMeasuredHeight());
}

The output for a view with only 1 child is still

12-14 10:17:04.902 3004-3004/? D/SomeTag: w: 0, h: 0

12-14 10:17:04.902 3004-3004/? D/SomeTag: mw: 0, mh: 0

So there is nothing wrong with your layout (except you do have a misnomer. You call the method logToolbarLayoutParams, but you aren't accessing the layout params at all. You are trying to get properties on the view object before the layout pass has occurred. Maybe this is your confusion). So what you're missing is an understanding of Android's layout system, viewgroups, and views. Romain Guy had a really cool talk at one point on Devoxx about how to build a custom FlowLayout. Either the site is down or the video is pulled but here's the code in GitHub If you look at the method onLayout, you can see that a ViewGroup loops through all of it's children and calls child.layout(). Until this method is called, the view.getWidth and view.getHeight methods will return 0. And this method is called by the OS whenver it schedules it. So basically, you are trying to access the width and height immediately even before the OS scheduled a layout. Make a custom viewgroup yourself, add some break points, and give it a shot.

Community
  • 1
  • 1
whizzle
  • 2,053
  • 17
  • 21
1

toolbar.getWidth() will tell you the width of the view after it has been measured and laid out.
After inflating the view its width and height will always be 0 because neither a measure() nor a layout() has occured.

protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   toolbar = (Toolbar) findViewById(R.id.toolbar);

   // check after inflation -> will be 0
   logToolbarLayoutParams();
}

onGlobalLayout() reports the correct data, because—as the name suggests—both, onMeasure() and onLayout() have been called. The dimensions of the view are known. This does not mean the view has been drawn. onDraw() is the third and last step.

It also does not make any difference of how complex your layout is or which views you are using. Measuring and layout passes don't happen immediately after the inflation of the view.


To get and work with the correct dimensions of your view you have 3 options:

  1. Use ViewTreeObserver.OnGlobalLayoutListener#onGlobalLayout() like you already suggested
  2. Check the size to a later time, when you can be sure the view has been drawn, (e.g. upon user interaction, in an OnClickListener)
  3. Go custom and create your own View. There you get the opportunity to handle all of onMeasure, onLayout, and onDraw yourself!
David Medenjak
  • 33,993
  • 14
  • 106
  • 134
0

Drawing views take considerable time but we can reduce by removing nested layout and make view hierarchy flat either by using RelativeLayout or Constrain layout.

To find overdraw. Select "Show overdraw areas" in Debug GPU overdraw developer options from settings.

Study this and this important article from developer.android on optimizing layouts topic

Qamar
  • 4,959
  • 1
  • 30
  • 49
-1

I've just solved same problem in same case. All solutions with ViewTreeObserver.OnGlobalLayoutListener() look's dirty and not works for me. The easiest way to know width and height at current screen looks like this:

toolbar.post(new Runnable() {
        @Override
        public void run() {
            int headerWidth = toolbar.getWidth();
            int headerHeight = toolbar.getHeight();
            // do whatever you want ...
        }
    });

view.post() will add your code in the end at view's message queue, when all sizes will already calculated. imho, that's obviously and more understandable, then OnGlobalLayoutListener(). Hope it will help you.

Anyway, this solution is just "delayed getting sizes", like a OnGlobalLayoutListener(). But this is normal behavior of system, it takes some time to draw views on the screen. Best way is not expecting calculated dimensions - instead you should coordinate all relationships between views in .xml files. Attributes like WRAP_CONTENT and MATCH_PARENT is easiest way to solve problems like this

dosssik
  • 79
  • 1
  • 8
-2

you try to get width and height of a view before its attached to screen you can create a custom view and wath you need in onAttach method

Ahmed.ess
  • 265
  • 3
  • 10
  • yes ahmed am aware of that. I want to understand why it taking much time. That's why I searched a little more using hierarchy viewer in ADB – HourGlass Dec 08 '16 at 17:17