1

In one of my activities, I'd like to have something like a 'menubar', positioned at the bottom of the screen in portrait mode and at the right of the screen in landscape mode.

The menubar is permanently visible and will house imagebuttons, which have the same height but may have different widths. According to the number of 'buttons' in the 'menubar' a proper padding is chosen, so that the available height or witdh is used properly. Basically it should look like this:

portrait landscape

I already considered using a 'split action bar', as suggested here. But in this case I only have the desired effect in portrait mode.

At the moment I consider to implement a custom gridview layout to get this effect, or to modify the dashboard pattern found here.

Maybe some of you already implemented something like a 'menubar like layout' and can point me in the right direction.

EDIT

I slightly modified the dashboard pattern code mentioned above, it's just a first proof of concept, but seems to do what I intended:

public class Nx1Layout extends ViewGroup {

private static final String TAG = "Nx1Layout";
private int mMaxChildWidth = 0;
private int mMaxChildHeight = 0;
private int mScreenOrientation = Configuration.ORIENTATION_PORTRAIT;

public Nx1Layout(Context context) {
    super(context, null);
}

public Nx1Layout(Context context, AttributeSet attrs) {
    super(context, attrs, 0);
}

public Nx1Layout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

public void setScreenOrientation(int screenOrientation) {
    mScreenOrientation = screenOrientation;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    mMaxChildWidth = 0;
    mMaxChildHeight = 0;

    // Measure once to find the maximum child size.
    int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST);
    int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.AT_MOST);
    final int count = getChildCount();
    for (int i = 0; i < count; i++) {
        final View child = getChildAt(i);
        if (child.getVisibility() == GONE) {
            continue;
        }

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);

        mMaxChildWidth = Math.max(mMaxChildWidth, child.getMeasuredWidth());
        mMaxChildHeight = Math.max(mMaxChildHeight, child.getMeasuredHeight());
    }

    // Measure again for each child to be exactly the same size.
    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxChildWidth, MeasureSpec.EXACTLY);
    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxChildHeight, MeasureSpec.EXACTLY);
    for (int i = 0; i < count; i++) {
        final View child = getChildAt(i);
        if (child.getVisibility() == GONE) {
            continue;
        }

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }
    setMeasuredDimension(resolveSize(mMaxChildWidth, widthMeasureSpec),resolveSize(mMaxChildHeight, heightMeasureSpec));
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    int width = r - l;
    int height = b - t;

    final int count = getChildCount();

    // Calculate the number of visible children.
    int visibleCount = 0;
    for (int i = 0; i < count; i++) {
        final View child = getChildAt(i);
        if (child.getVisibility() == GONE) {
            continue;
        }
        ++visibleCount;
    }

    if (visibleCount == 0) {
        return;
    }

    // Horizontal and vertical space between items
    int hSpace = 0;
    int vSpace = 0;

    int cols, rows;

    if(mScreenOrientation == Configuration.ORIENTATION_PORTRAIT) {
        cols = visibleCount;
        rows = 1;
    } else {
        cols = 1;
        rows = visibleCount;
    }

    hSpace = ((width - mMaxChildWidth * cols) / (cols + 1));
    vSpace = ((height - mMaxChildHeight * rows) / (rows + 1));

    // Lay out children based on calculated best-fit number of rows and cols.
    // If we chose a layout that has negative horizontal or vertical space, force it to zero.
    hSpace = Math.max(0, hSpace);
    vSpace = Math.max(0, vSpace);

    // Re-use width/height variables to be child width/height.
    width = (width - hSpace * (cols + 1)) / cols;
    height = (height - vSpace * (rows + 1)) / rows;

    int left, top;
    int col, row;
    int visibleIndex = 0;
    for (int i = 0; i < count; i++) {
        final View child = getChildAt(i);
        if (child.getVisibility() == GONE) {
            continue;
        }

        row = visibleIndex / cols;
        col = visibleIndex % cols;

        left = hSpace * (col + 1) + width * col;
        top = vSpace * (row + 1) + height * row;

        child.layout(left, top, (hSpace == 0 && col == cols - 1) ? r : (left + width), (vSpace == 0 && row == rows - 1) ? b : (top + height));
        ++visibleIndex;
    }
}
}

Here's some activity code to test it:

public class TestActivity extends SherlockFragmentActivity {

 @Override
 public void onCreate(Bundle savedInstanceState) {
     // setup ui
     super.onCreate(savedInstanceState);
     setContentView(R.layout.ui_test);

     Nx1Layout layout = (Nx1Layout)findViewById(R.id.layout1);
     layout.setScreenOrientation(getScreenOrientation());
 }

 public int getScreenOrientation()
 {
     Display getOrient = getWindowManager().getDefaultDisplay();
     int orientation = Configuration.ORIENTATION_UNDEFINED;
     if(getOrient.getWidth() == getOrient.getHeight()){
         orientation = Configuration.ORIENTATION_SQUARE;
     } else{ 
         if(getOrient.getWidth() < getOrient.getHeight()){
             orientation = Configuration.ORIENTATION_PORTRAIT;
         }else { 
              orientation = Configuration.ORIENTATION_LANDSCAPE;
         }
     }
     return orientation;
 }}

here's the layout file for portrait mode:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
   <com.yourpackagename.Nx1Layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="70dp"
    android:id="@+id/layout1">

                <ImageView
                    android:id="@+id/image1"
                    android:layout_width="70dp"
                    android:layout_height="70dp"
                    android:contentDescription="some description"
                    android:scaleType="centerInside"
                    android:padding="2dp"
                    android:src="@drawable/test_draw" />

                <ImageView
                    android:id="@+id/image2"
                    android:layout_width="70dp"
                    android:layout_height="70dp"
                    android:contentDescription="some description"
                    android:scaleType="centerInside"
                    android:padding="2dp"
                    android:src="@drawable/test_draw" />

                <ImageView
                    android:id="@+id/image3"
                    android:layout_width="70dp"
                    android:layout_height="70dp"
                    android:contentDescription="some description"
                    android:scaleType="centerInside"
                    android:padding="2dp"
                    android:src="@drawable/test_draw" />

    </com.yourpackagename.Nx1Layout>
</LinearLayout>

and here the layout file for landscape mode:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
   <com.yourpackagename.Nx1Layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="70dp"
    android:layout_height="match_parent"
    android:id="@+id/layout1">

                <ImageView
                    android:id="@+id/image1"
                    android:layout_width="70dp"
                    android:layout_height="70dp"
                    android:contentDescription="some description"
                    android:scaleType="centerInside"
                    android:padding="2dp"
                    android:src="@drawable/test_draw" />

                <ImageView
                    android:id="@+id/image2"
                    android:layout_width="70dp"
                    android:layout_height="70dp"
                    android:contentDescription="some description"
                    android:scaleType="centerInside"
                    android:padding="2dp"
                    android:src="@drawable/test_draw_narrow" />

                <ImageView
                    android:id="@+id/image3"
                    android:layout_width="70dp"
                    android:layout_height="70dp"
                    android:contentDescription="some description"
                    android:scaleType="centerInside"
                    android:padding="2dp"
                    android:src="@drawable/test_draw" />
    </com.yourpackagename.Nx1Layout>
</LinearLayout>

last but not least some drawable I used:

test draw

Feel free to comment on this solution...

Community
  • 1
  • 1
darksaga
  • 2,166
  • 2
  • 18
  • 21
  • 2
    I don't see where do you have problems. That "menubar" could easily be implemented with one of the current layouts(`LinearLayout`, `Relativelayout`) and you would add it to the current layout in the desired orientation(or even attach it directly to the content `FrameLayout`) if you have as the root one of the layouts that stack the children(`RelativeLayout`, `FrameLayout`). – user Oct 22 '12 at 13:57
  • I'm using a `Relativelayout` at the moment. What I'd like is that the 1 x N grid automatically adjusts the horizontal whitespaces between items in portrait mode & the vertical whitespaces between items in landscape mode, so that the items are evenly distibuted, using all the width in portrait and all the height in landscape mode. – darksaga Oct 22 '12 at 15:34
  • If you are willing to switch to a `LinearLayout`(and I don't see any real reasons to use the `RelativeLayout` instead) for the menubar that the even spacing it's easy(horizontally or vertically). Just insert empty views between the menubar elements with `layout_weight` set to `1`. – user Oct 22 '12 at 15:37
  • I don't think using a `LinearLayout` + empty views with layout_weight set to 1 will automatically scale my 'menuitems' + give me even spacings. Didn't have much time today to invest this further, but I came up with a solution, which does what I wanted. Will post it in a sec... – darksaga Oct 22 '12 at 17:46

0 Answers0