I have list of button in bottom of the page which is in horizontal listview, i want to show only 4 row in listview, when screen become bigger it's item size should also become bigger so only 4 item shows.
for example
here you can see that after increasing size of width it's related horizontal listview's listitem also increasing
is it possible? if possible than can any body suggest me how we can handle it ?
Create one custom layout class like below..
public class MyLinearLayout extends LinearLayout {
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyLinearLayout(Context context) {
super(context);
}
public void setLayoutParams(int width) {
LayoutParams params = new LayoutParams(width / 4,
LayoutParams.WRAP_CONTENT);
this.setLayoutParams(params);
}
#Override
public void setLayoutParams(android.view.ViewGroup.LayoutParams params) {
super.setLayoutParams(params);
}
}
put this horizontal scrollview in your xml file
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<com.example.widget.MyLinearLayout
android:id="#+id/llMainHome"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/orange_bg"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/home" />
</com.example.widget.MyLinearLayout>
<com.example.widget.MyLinearLayout
android:id="#+id/llHomeSearch"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/green_bg"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/search" />
</com.example.widget.MyLinearLayout>
<com.example.widget.MyLinearLayout
android:id="#+id/llHomeFavorite"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/green_bg"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/favorite" />
</com.example.widget.MyLinearLayout>
<com.example.widget.MyLinearLayout
android:id="#+id/llHomeGrocery"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/green_bg"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/make_juice" />
</com.example.widget.MyLinearLayout>
<com.example.widget.MyLinearLayout
android:id="#+id/llHomeSettings"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/green_bg"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/settings" />
</com.example.widget.MyLinearLayout>
</LinearLayout>
</HorizontalScrollView>
And in your activity class file declare
private MyLinearLayout llHomeSearch, llHomeFavorite,
llHomeGrocery, llHomeSettings,llMainHome;
oncreate Method code is
llHomeFavorite = (MyLinearLayout) findViewById(R.id.llHomeFavorite);
llHomeFavorite.setOnClickListener(this);
llMainHome = (MyLinearLayout) findViewById(R.id.llMainHome);
llMainHome.setOnClickListener(this);
llHomeSearch = (MyLinearLayout) findViewById(R.id.llHomeSearch);
llHomeSearch.setOnClickListener(this);
llHomeGrocery = (MyLinearLayout) findViewById(R.id.llHomeGrocery);
llHomeGrocery.setOnClickListener(this);
llHomeSettings = (MyLinearLayout) findViewById(R.id.llHomeSettings);
llHomeSettings.setOnClickListener(this);
Display display = getWindowManager().getDefaultDisplay();
Point size = getDisplaySize(display);
int width = size.x;
llMainHome.setLayoutParams(width);
llHomeFavorite.setLayoutParams(width);
llHomeGrocery.setLayoutParams(width);
llHomeSearch.setLayoutParams(width);
llHomeSettings.setLayoutParams(width);
and getDisplaysize method is
#SuppressLint("NewApi")
private static Point getDisplaySize(final Display display) {
final Point point = new Point();
try {
display.getSize(point);
} catch (java.lang.NoSuchMethodError ignore) { // Older device
point.x = display.getWidth();
point.y = display.getHeight();
}
return point;
}
here you go..it will work nice..
there is no need to take horizontal list view if you have fix number of item in your tab bar..
Maybe try to get Screen width and then set List's element to 1/4 of that width?
Something like in onResume/onCreate
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
width = size.x; //remember that width
And in getView
LayoutParams params=new LayoutParams(width/4, -1);
element.setLayoutParams(params)
Related
I created a new small example to explain my new problem. In the example I created a RelativeLayout that fills the whole screen. And 3 children :
Custom view (PView) created to draw proportional view that must fill all free space by width in portrait mode and free space by height in landscape mode without overlay on top and bottom of FrameLayout (pink)
FrameLayout with id top that must show above middle (red)
FrameLayout with id bottom that must show below middle (yellow)
But now in landscape mode middle item overdraw top and bottom. Have anyone idieas how to fix it ?
layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/top"
android:layout_width="100dp"
android:layout_height="24dp"
android:layout_above="#+id/middle"
android:layout_centerHorizontal="true"
android:background="#FFFF0000" />
<test.com.heighttest.PView
android:id="#+id/middle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="#FFFF00FF" />
<FrameLayout
android:id="#+id/bottom"
android:layout_width="100dp"
android:layout_height="24dp"
android:layout_below="#+id/middle"
android:layout_centerHorizontal="true"
android:background="#FFFFFF00" />
</RelativeLayout>
PView.java
package test.com.heighttest;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
/**
* Created by Anton Potekhin (Anton.Potekhin#gmail.com) on 26.09.16.
*/
public class PView extends RelativeLayout {
public static final int USE_FOR_SCALE_WIDTH = 0;
public static final int USE_FOR_SCALE_HEIGHT = 1;
public int getUseForScale() {
return useForScale;
}
public void setUseForScale(int useForScale) {
this.useForScale = useForScale;
}
private int useForScale = 0;
public float getAspectRatio() {
return aspectRatio;
}
public void setAspectRatio(float aspectRatio) {
this.aspectRatio = aspectRatio;
}
/**
* Aspect ratio to calculate size of view. Set 0 to not use aspect ratio (Works like RelativeLayout).
*/
private float aspectRatio = 0;
public PView(Context context) {
super(context);
}
public PView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Use aspect ratio only if it more than 0
if (aspectRatio > 0) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (useForScale == USE_FOR_SCALE_WIDTH) {
height = Math.round(width / aspectRatio);
} else {
width = Math.round(height * aspectRatio);
}
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
MainActivity.java
package test.com.heighttest;
import android.content.res.Configuration;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private PView middleView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
com.facebook.stetho.Stetho.initializeWithDefaults(this);
setContentView(R.layout.activity_main);
middleView = (PView) findViewById(R.id.middle);
middleView.setAspectRatio(1.2f);
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
middleView.setUseForScale(PView.USE_FOR_SCALE_HEIGHT);
} else {
middleView.setUseForScale(PView.USE_FOR_SCALE_WIDTH);
}
}
}
Screenshot in portrait mode (Works correctly):
Screenshot in landscape mode (Works incorrect because middle overdraw top and bottom):
Screenshot what i want to get in landscape mode
Solution by #nidhi-pandya (with my fixes):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<FrameLayout
android:id="#+id/top"
android:layout_width="100dp"
android:layout_height="24dp"
android:background="#FFFF0000" />
<test.com.heighttest.PView
android:id="#+id/middle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FFFF00FF" />
<FrameLayout
android:id="#+id/bottom"
android:layout_width="100dp"
android:layout_height="24dp"
android:background="#FFFFFF00" />
</LinearLayout>
</RelativeLayout>
Add LinearLayout below Relativelayout and use its orientation to arrange your content vertically. Use alignparenttop, alignparentbottom and centerinparent attribute. It will give you the same output in both orientation.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<FrameLayout
android:id="#+id/top"
android:layout_width="80dp"
android:layout_height="50dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="15dp"
android:background="#FFFF0000" />
<test.com.heighttest.PView
android:id="#+id/middle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="#FFFF00FF" />
<FrameLayout
android:id="#+id/bottom"
android:layout_width="80dp"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="15dp"
android:background="#FFFFFF00" />
</LinearLayout>
</RelativeLayout>
SOLVED CHECK ANSWER BELOW...
So I am trying to create a comments functionality for my Android app and I want to display the comments inside a recyclerview and then have a button and textview below the recyclerview to add comments. I want to have the recyclerview a certain height and make it scrollable if there are lots of comments because I dont want the users to have to scroll down the screen to find the add button.
I couldn't get it to work so I was wondering if anyone else had that issue.
I have all the adapter and everything set up, I am just having trouble with the recyclerview.
Thanks.
I prob was not clear on what I was trying to accomplish. I am trying to create a cardview where it will display all the comments and the ability to add a new comment. The recyclerview will take up approx 80% of the height and then the last 20% is for the edittext and button.
My XML (Scroll to last cardview where the recyclerview is)
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/scrollview">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:fab="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ProfilePageActivity"
>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/profilepagetoolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:popupTheme="#style/ThemeOverlay.AppCompat.Light"
android:minHeight="?attr/actionBarSize">
</android.support.v7.widget.Toolbar>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:layout_marginTop="35dp"
android:layout_below="#+id/profilepagetoolbar"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:id="#+id/aboutCard">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:gravity="center_vertical"
android:orientation="vertical"
android:layout_alignTop="#+id/aboutCard"
android:focusable="true"
android:focusableInTouchMode="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="-60dp"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#color/text"
android:textSize="20sp"
android:text="ABOUT" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#color/dividers" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="10dp">
<ImageView
android:id="#+id/nameicon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_margin="8dp"
android:transitionName="appIcon"
android:background="#drawable/ic_account_circle_black_24dp"/>
<TextView
android:id="#+id/Name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#color/secondary"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="10dp">
<ImageView
android:id="#+id/locationicon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_margin="8dp"
android:transitionName="appIcon"
android:background="#drawable/ic_map_black_24dp"/>
<TextView
android:id="#+id/Location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="11dp"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#color/secondary"
android:textSize="15sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="10dp">
<ImageView
android:id="#+id/websiteIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_margin="8dp"
android:transitionName="appIcon"
android:background="#drawable/ic_explore_black_24dp"/>
<TextView
android:id="#+id/Website"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="11dp"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#color/secondary"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:layout_marginTop="35dp"
android:layout_below="#+id/aboutCard"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:id="#+id/writeComment"
android:layout_alignParentTop="false"
android:layout_alignParentBottom="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:gravity="center_vertical"
android:orientation="vertical"
android:focusable="true"
android:focusableInTouchMode="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="-100dp"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#color/text"
android:textSize="20sp"
android:text="Comments" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#color/dividers"
android:id="#+id/divider"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1">
<EditText
android:layout_width="244dp"
android:layout_height="wrap_content"
android:id="#+id/editComment"
android:layout_below="#+id/divider"
android:textColor="#color/text"
android:hint="Write a comment..."/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Create"
android:id="#+id/btnComment"
android:layout_gravity="center_horizontal" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:layout_marginTop="20dp"
android:layout_below="#+id/writeComment"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:id="#+id/commentsCard">
<LinearLayout
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="0dp"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#color/text"
android:textSize="20sp"
android:text="Comments" />
<android.support.v7.widget.RecyclerView
android:id="#+id/commentsList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusableInTouchMode="true" />
</LinearLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
</ScrollView>
The second and first comment are being cut off.
So what my problem was that for some reason, Recyclerview didnt wrap_contents. I did some research (thanks stackoverflow) and found out a lot of people were having this issue and they posted solutions for this issue.
Basically, I had to use a customized linearlayoutmanger to fix the issue.
I will post the solution they posted and links to their questions. thanks for whoever tried to help, I appreciate it.
This is the extra file I needed. And then I had to set my recyclerview to use this layout instead of the default one.
public class MyLinearLayoutManager extends LinearLayoutManager {
public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
private int[] mMeasuredDimension = new int[2];
#Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
int widthSpec, int heightSpec) {
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int width = 0;
int height = 0;
for (int i = 0; i < getItemCount(); i++) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
if (getOrientation() == HORIZONTAL) {
width = width + mMeasuredDimension[0];
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
height = height + mMeasuredDimension[1];
if (i == 0) {
width = mMeasuredDimension[0];
}
}
}
switch (widthMode) {
case View.MeasureSpec.EXACTLY:
width = widthSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
switch (heightMode) {
case View.MeasureSpec.EXACTLY:
height = heightSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
setMeasuredDimension(width, height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
View view = recycler.getViewForPosition(position);
if (view != null) {
RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
getPaddingLeft() + getPaddingRight(), p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
getPaddingTop() + getPaddingBottom(), p.height);
view.measure(childWidthSpec, childHeightSpec);
measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
recycler.recycleView(view);
}
}
}
After that. Change this:
mProductsRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
To this:
mRecyclerView.setLayoutManager(new MyLinearLayoutManager(getApplicationContext(),1,false));
Three new paramets(Context, int Orientation, boolean reverse);
basically, i put 1 for orientation so it shows vertiacally, and false for revers so it shows up how it is ordered in my List.
Links to other people's question with same problem as me.
Nested Recycler view height doesn't wrap its content
Nested Recycler view height doesn't wrap its content
Thanks once again guys. Hope this helps someone else
Add this code in your activity, will set the height of your recycler view to the 90% of user's screen window.
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int a = (displaymetrics.heightPixels*90)/100;
recylcerView.getLayoutParams().height =a;
and your comment layout below the your recyclerView
like this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/mudit"
>
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="5dp"
android:scrollbars="vertical" />
</LinearLayout>
<RelativeLayout
android:layout_below="#+id/mudit"
android:id="#+id/rl_commentWrap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" >
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:ems="10" />
<Button
android:id="#+id/plusButton"
style="android:buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="Send"
android:textColor="#FFFFFF"
android:translationZ="5dp" />
</RelativeLayout>
</RelativeLayout>
In my situation I had a DialogFragment, in which there are 2 recyclers and 2 horizontal linear layouts with 2 buttons.
Dialog from top to bottom looks like this:
RecyclerView A
Horizontal linear layout X with 2 buttons
RecyclerView B
Horizontal linear layout Y with 2 buttons
On top of that both recyclers size is dynamic.
Recycler A size can change based on user swipes in both recyclers.
Recycler B size can change based on its item click listener.
What I wanted to achieve was to cut the Dialog from top to bottom
and have each of those four views its constant part of the Dialog height.
What worked was to divide it first to 2 separate relative layouts, say lTOP and lBottom. Set lTOP alignParentTop, lBottom alignParentBottom and layout_below lTOP.
Both of them width match_parent, height wrap_content.
Then in each of them create 1 relative (say lINTop) and 1 linear (say lINBottom) layouts. lINTop has recycler, lINBottom has 2 buttons.
Set both lINTop lINBottom width match_parent, height wrap_content.
Set lINTop alignParentTop, lINBottom alignParentBottom and below lINTop.
Set lINTop orientation vertical, lINBottom orientation horizontal.
Set recyclers width match_parent, height wrap_content.
Then i putted this all inside single relative layout with width/height wrap_content and orientation vertical.
Then this inside scrollview with width/height match_parent and orientation vertical.
Then needed a little code magic for setting up recycler in onCreateView:
For Recycler A:
private void setupRecyclerA() {
// use a linear layout manager
RecyclerView.LayoutManager layManUS = new LinearLayoutManager(setupActivity().get());
recyclerA.setLayoutManager(layManUS);
recyclerA.addItemDecoration(new DividerItemDecoration(
setupActivity().get(), LinearLayoutManager.VERTICAL));
recyclerA.setNestedScrollingEnabled(true);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerA.setHasFixedSize(true);
}
For Recycler B:
private void setupRecyclerB() {
// use a linear layout manager
RecyclerView.LayoutManager layManUS = new LinearLayoutManager(setupActivity().get());
recyclerB.setLayoutManager(layManUS);
recyclerB.addItemDecoration(new DividerItemDecoration(
setupActivity().get(), LinearLayoutManager.VERTICAL));
recyclerB.setNestedScrollingEnabled(true);
// set fixed height
DisplayMetrics displaymetrics = new DisplayMetrics();
setupActivity().get().getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
// set height to 30 percent of dialog
int a = (displaymetrics.heightPixels*30)/100;
recyclerB.getLayoutParams().height =a;
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerB.setHasFixedSize(true);
}
I didnt invented it, I just combined solutions from many different Stack Overflow questions which I dont even remember now, sorry and thanks to the Creators.
I had a similar problem and solved it with RelativeLayout. I have this layout:
I wanted the top and bottom cardview to stay in place while scrolling the central recyclerView. Tried with LinearLayout and ConstraintLayout but didn't work, the bottom CardView only was shown when I scrolled to the end of the recycler.
This is my code, notice the layout_above, layout_below, and layout_alignParentBottom attributes:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/grisMasOscuro">
<androidx.cardview.widget.CardView
android:id="#+id/cv1"
android:layout_width="match_parent"
android:layout_height="50dp" >
<!-- cardview content -->
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/cv3"
android:layout_below="#id/cv1">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/myRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="#+id/cv3"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true">
<!-- cardview content -->
</androidx.cardview.widget.CardView>
</RelativeLayout>
I found another solution.
If you will wrap recyclerview in RelativeLayout, it will solve the problem easily.
Thanks.
IMPORTANT:
I want to draw content of a View A to a bitmap and part of the View A is a TextView which text has to be centered horizontally. The View A is not displayed nor is part of another View.
QUESTION:
How can I tell the TextView to display the text correctly when it is drawn to a bitmap????
My base layout(base_layout.xml):
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:baselineAligned="false" >
<TextView
android:id="#+id/dateTV"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginRight="5dp"
android:gravity="center"
android:padding="3dp"
android:textStyle="bold" />
<TextView
android:id="#+id/shiftsListTV"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:singleLine="false"
android:maxLines="2"
android:padding="3dp" />
</LinearLayout>
My TestActivity.java activity, which I use for testing:
public class TestActivity extends Activity {
private LinearLayout mainHolderLL;
#Override
protected int getLayoutXml() {
return R.layout.activity_test;
}
#Override
protected final void onCreate(Bundle savedInstanceState) {
mainHolderLL = (LinearLayout) findViewById(R.id.mainHolderLL);
View baseLayoutView = View.inflate(context, R.layout.base_layout, null);
dateTV.setText("Feb 2014");
shiftsListTV.setText("shift1, shift2");
int width = 500;
int height = 500;
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
baseLayoutView.measure(widthMeasureSpec, heightMeasureSpec);
baseLayoutView.layout(0, 0, baseLayoutView.getMeasuredWidth(), baseLayoutView.getMeasuredHeight());
Bitmap bitmap = Bitmap.createBitmap(baseLayoutView.getMeasuredWidth(), baseLayoutView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
baseLayoutView.draw(canvas);
ImageView appwidget_image_view = (ImageView) findViewById(R.id.appwidget_image_view);
appwidget_image_view.setImageBitmap(bitmap);
}
}
activity_test.xml:
<HorizontalScrollView 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" >
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="#+id/mainHolderLL"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="#dimen/common_padding_normal" >
<ImageView
android:id="#+id/appwidget_image_view"
android:layout_width="294dp"
android:layout_height="294dp"
android:background="#android:color/black"
android:cropToPadding="false"
android:padding="#dimen/widget_margin"
android:scaleType="fitXY"
tools:ignore="ContentDescription" />
</LinearLayout>
</ScrollView>
</HorizontalScrollView>
If the bitmap is displayed inside a ImageView, the text inside dateTV TextView is not centered horizontally and it looks as crushed(on Android 4.3 but on Android 2.3.3 nothing is displayed), but the text inside shiftsListTV is displayed correctly.
If I remove the android:gravity attribute from dateTv TextView the text inside dateTV is displayed correctly but is not centered. I need the text centered.
Edit:
After some research I found out that TextView has a problem with gravity tag.
The imageview is NOT important it is solely for displaying the bitmap.
I have to define 5 layouts on the screen and place them like a 3x3 grid. Layouts is empty.
At some moment I want programmatically to add some view on one layout and that view mustn't grows over allocated size of layout. In other words I want to have layout in which to put any view and it will be guaranty that it won't grows over that layout. Important note: I don't have rights to change manually size of added view, I only can to control its maximum size.
I have right now such layout:
<RelativeLayout
android:id="#+id/pluginsLayout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/mainButtons"
android:layout_below="#+id/paramsLayout">
<RelativeLayout
android:id="#+id/capturingPluginLayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="fill_horizontal|left"
android:layout_above="#+id/processingPluginLayout">
</RelativeLayout>
<RelativeLayout
android:id="#+id/processingPluginLayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="fill_horizontal|left"
android:layout_above="#+id/filterPluginLayout">
</RelativeLayout>
<RelativeLayout
android:id="#+id/filterPluginLayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="fill_horizontal|left|bottom"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true">
</RelativeLayout>
<RelativeLayout
android:id="#+id/exportPluginLayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="fill_horizontal|right"
android:layout_above="#+id/viewfinderPluginLayout">
</RelativeLayout>
<RelativeLayout
android:id="#+id/viewfinderPluginLayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="fill_horizontal|bottom|right"
android:layout_toLeftOf="#+id/filterPluginLayout"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true">
</RelativeLayout>
</RelativeLayout>
And I added new view in code:
public void addVFPluginView(View view)
{
((RelativeLayout)MainScreen.thiz.findViewById(R.id.viewfinderPluginLayout)).addView(view);
}
I expect to got like this behaviour:
But I got only this, view fill entire parent layout:
Note: I use API8 (don't have GridLayout)
u can use grid layout in API8.
I've managed to solve this issue.
The main idea was to control view's sizes by myself programmatically.
I calculate appropriate proportion for each zone and when somebody add a new view to some of this layout I check suitability of the size of this view to the allocated size of layout. If size is not suitable I modify LayoutParams for this View.
Here is the xml of empty layouts:
<RelativeLayout
android:id="#+id/pluginsLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/mainButtons"
android:layout_below="#+id/paramsLayout">
<LinearLayout
android:id="#+id/capturePluginLayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true">
</LinearLayout>
<LinearLayout
android:id="#+id/processingPluginLayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true">
</LinearLayout>
<LinearLayout
android:id="#+id/filterPluginLayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true">
</LinearLayout>
<LinearLayout
android:id="#+id/exportPluginLayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true">
</LinearLayout>
<RelativeLayout
android:id="#+id/viewfinderPluginLayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true">
</RelativeLayout>
</RelativeLayout>
And like that I manage the size of adding views:
public void addVFPluginView(View view)
{
//Get maximum width and height for such plugins
int layoutHeight = this.getViewfinderLayoutHeight();
int layoutWidth = this.getViewfinderLayoutWidth();
//Calculate appropriate size of added plugin's view
android.widget.RelativeLayout.LayoutParams viewLayoutParams = (android.widget.RelativeLayout.LayoutParams)view.getLayoutParams();
viewLayoutParams = this.getTunedRelativeLayoutParams(view, viewLayoutParams, layoutWidth, layoutHeight);
//Get fixed maximum size for this plugin type
public int getViewfinderLayoutWidth()
{
return ((RelativeLayout)MainScreen.thiz.findViewById(R.id.pluginsLayout)).getWidth()/2;
}
public int getViewfinderLayoutHeight()
{
return (int)(((RelativeLayout)MainScreen.thiz.findViewById(R.id.pluginsLayout)).getHeight()*0.7);
}
((RelativeLayout)MainScreen.thiz.findViewById(R.id.viewfinderPluginLayout)).addView(view, viewLayoutParams);
}
android.widget.RelativeLayout.LayoutParams getTunedRelativeLayoutParams(View view, android.widget.RelativeLayout.LayoutParams currParams, int goodWidth, int goodHeight)
{
int viewHeight, viewWidth;
if(currParams != null)
{
viewHeight = currParams.height;
viewWidth = currParams.width;
if(viewHeight > goodHeight || viewHeight <= 0)
viewHeight = goodHeight;
if(viewWidth > goodWidth || viewWidth <= 0)
viewWidth = goodWidth;
currParams.width = viewWidth;
currParams.height = viewHeight;
view.setLayoutParams(currParams);
}
else
{
currParams = new android.widget.RelativeLayout.LayoutParams(goodWidth, goodHeight);
view.setLayoutParams(currParams);
}
return currParams;
}
Finally, next issue is for several views with suitable sizes but in sum they're bigger than allocated size. Maybe I'll just straightly count sizes of views and if the sum with the size of next adding view will be more than allocated size I just disallow to add this view.
I am trying to implement the layout below:
I guess GridLayout is suitable for my needs but after 2 hours of struggle I couldn't create even a similar layout.. The layout is resizing itself wrongly, it exceeds the screen of the phone and it also does not span the specified rows and columns.
Here I selected a button so you can see how it exceeds the boundaries:
and here is the associated xml code: https://gist.github.com/2834492
I have reached a similar layout with nested linearlayouts but it's not possible to properly resize it for different screen sizes.
UPDATE - approximate LinearLayout implementation:
The XML code: https://gist.github.com/cdoger/2835887
However, the problem is it does not resize itself properly here some screenshots with different screen configurations:
TLDR: Can someone show me a heterogeneous layout implementation with GridLayout like in the first picture?
The issue you are facing is due to inappropriate use of the GridLayout. The GridLayout is made to show its children in a grid and you are trying to override that without extending the GridLayout. While what you want may be accomplished in code (utilizing numcolumns and columnsize), it will not be useful for multiple screen sizes without a heck of a lot of code.
The only adequate solution that won't require a ton of hacking is judicious use of both LinearLayout and RelativeLayout. LinearLayout should not be used exclusively as it is made to drop items in a line (horizontally or vertically only). This becomes especially apparent when you try and do the bottom four buttons. While the buttons above may be done with LinearLayout with very little effort, RelativeLayout is what you need for the bottom four buttons.
Note:
RelativeLayout can be a little bit tricksy for those with little experience using them. Some pitfalls include: children overlapping, children moving off the screen, height and width rendering improperly applied. If you would like an example, let me know and I will edit my answer.
Final Note:
I'm all for utilizing the current framework objects in unique ways, and genuinely prefer to provide the requested solution. The solution, however, is not viable given the constraints of the question.
(Revision) Solution 1
After some careful thought last night, this may be accomplished with a pure LinearLayout. While I do not like this solution, it should be multi-screen friendly and requires no tooling around from me. Caution should be used with too many LinearLayouts, as according to Google's developers, it can result in slow loading UIs due to the layout_weight property. A second solution utilizing RelativeLayout will be provided when I return home. Now Tested This provides the desired layout parameters on all screen-sizes and orientations.
<?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" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<Button
android:id="#+id/Button01"
android:layout_width="0"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button" />
<Button
android:id="#+id/Button02"
android:layout_width="0"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button" />
</LinearLayout>
<Button
android:id="#+id/button3"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Button" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.00"
android:orientation="horizontal">
<Button
android:id="#+id/button1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button" />
<Button
android:id="#+id/button2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical" >
<Button
android:id="#+id/button4"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Button" />
<Button
android:id="#+id/button5"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:text="Button" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical" >
<Button
android:id="#+id/button6"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:text="Button" />
<Button
android:id="#+id/button7"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Button" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
Solution 1 Explanation
The key to LinearLayouts is to define your imperatives as separate Layouts and nest the others in them. As you apply constraints to more dimensions, more LinearLayouts must be added to encapsulate the others. For yours, it was crucial to have two more parents in order to maintain the proportion. A great indicator of when you should add another level is when you have to utilize layout_weight using anything other than an integer value. It simply becomes to hard to calculate properly. From there it was relatively simple to break it into columns.
Solution 2 (Failed)
While I was able to achieve desirable results utilizing RelativeLayout and "struts", I could only do so with layouts that were multiples of 2 buttons in height. Such a trick would be awesome as the levels of layout are greatly reduced, so I will work on a pure XML solution and post the answer here if and when I achieve it. In the meantime, the LinearLayout above should suit your needs perfectly.
I read this thread and realised that I wanted a flatter solution than those with linear layout. After some research I ended up making my own layout. It is inspired by a GridLayout but differs a bit.
Please note that if you are going to copy-paste the code you'll need to change package names in some places.
This layout has 4 layout parameters that children use to position themselves.These are layout_left, layout_top, layout_right, layout_bottom. The ICGridLayout itself has two attributes: layout_spacing and columns.
Columns tells the layout how many columns you want it to contain. It will then calculate the size of a cell with the same height as width. Which will be the layouts width/columns.
The spacing is the amount of space you want between each child.
The layout_left|top|right|bottom attributes are the coordinates for each side. The layout does no calculations in order to avoid collision or anything. It just puts the children where they want to be.
If you'd like to have smaller squares you just have to increase the columns attribute.
Keep in mind that this is a quick prototype, I will continue working on it and when I feel that it's ready I'll upload it to Github and put a comment here.
All of my code below should produce the following result:
*****EDIT*****
Added the call to measure for the children, forgot that the first time around.
END EDIT
ICGridLayout.java:
package com.risch.evertsson.iclib.layout;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.risch.evertsson.iclib.R;
/**
* Created by johanrisch on 6/13/13.
*/
public class ICGridLayout extends ViewGroup {
private int mColumns = 4;
private float mSpacing;
public ICGridLayout(Context context) {
super(context);
}
public ICGridLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public ICGridLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
private void init(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(
attrs,
R.styleable.ICGridLayout_Layout);
this.mColumns = a.getInt(R.styleable.ICGridLayout_Layout_columns, 3);
this.mSpacing = a.getDimension(R.styleable.ICGridLayout_Layout_layout_spacing, 0);
a.recycle();
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
int width = (int) (r - l);
int side = width / mColumns;
int children = getChildCount();
View child = null;
for (int i = 0; i < children; i++) {
child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int left = (int) (lp.left * side + mSpacing / 2);
int right = (int) (lp.right * side - mSpacing / 2);
int top = (int) (lp.top * side + mSpacing / 2);
int bottom = (int) (lp.bottom * side - mSpacing / 2);
child.layout(left, top, right, bottom);
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureVertical(widthMeasureSpec, heightMeasureSpec);
}
private void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width = 0;
int height = 0;
if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.EXACTLY) {
width = MeasureSpec.getSize(widthMeasureSpec);
} else {
throw new RuntimeException("widthMeasureSpec must be AT_MOST or " +
"EXACTLY not UNSPECIFIED when orientation == VERTICAL");
}
View child = null;
int row = 0;
int side = width / mColumns;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.bottom > row) {
row = lp.bottom;
}
int childHeight = (lp.bottom - lp.top)*side;
int childWidth = (lp.right-lp.left)*side;
int heightSpec = MeasureSpec.makeMeasureSpec(childHeight, LayoutParams.MATCH_PARENT);
int widthSpec = MeasureSpec.makeMeasureSpec(childWidth, LayoutParams.MATCH_PARENT);
child.measure(widthSpec, heightSpec);
}
height = row * side;
// TODO: Figure out a good way to use the heightMeasureSpec...
setMeasuredDimension(width, height);
}
#Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new ICGridLayout.LayoutParams(getContext(), attrs);
}
#Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof ICGridLayout.LayoutParams;
}
#Override
protected ViewGroup.LayoutParams
generateLayoutParams(ViewGroup.LayoutParams p) {
return new ICGridLayout.LayoutParams(p);
}
#Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams();
}
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
int right = 1;
int bottom = 1;
int top = 0;
int left = 0;
int width = -1;
int height = -1;
public LayoutParams() {
super(MATCH_PARENT, MATCH_PARENT);
top = 0;
left = 1;
}
public LayoutParams(int width, int height) {
super(width, height);
top = 0;
left = 1;
}
public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(
attrs,
R.styleable.ICGridLayout_Layout);
left = a.getInt(R.styleable.ICGridLayout_Layout_layout_left, 0);
top = a.getInt(R.styleable.ICGridLayout_Layout_layout_top, 0);
right = a.getInt(R.styleable.ICGridLayout_Layout_layout_right, left + 1);
bottom = a.getInt(R.styleable.ICGridLayout_Layout_layout_bottom, top + 1);
height = a.getInt(R.styleable.ICGridLayout_Layout_layout_row_span, -1);
width = a.getInt(R.styleable.ICGridLayout_Layout_layout_col_span, -1);
if (height != -1) {
bottom = top + height;
}
if (width != -1) {
right = left + width;
}
a.recycle();
}
public LayoutParams(ViewGroup.LayoutParams params) {
super(params);
}
}
}
ICGridLayout.java is pretty straight forward. It takes the values provided by the children and lays them out.
attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ICGridLayout_Layout">
<attr name="columns" format="integer"/>
<attr name="layout_left" format="integer"/>
<attr name="layout_top" format="integer"/>
<attr name="layout_right" format="integer"/>
<attr name="layout_bottom" format="integer"/>
<attr name="layout_col_span" format="integer"/>
<attr name="layout_row_span" format="integer"/>
<attr name="layout_spacing" format="dimension"/>
</declare-styleable>
</resources>
example_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.rischit.projectlogger"
android:id="#+id/scroller"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.risch.evertsson.iclib.layout.ICGridLayout
android:id="#+id/ICGridLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_spacing="4dp"
app:columns="4" >
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_bottom="1"
app:layout_left="0"
app:layout_right="4"
app:layout_top="0"
android:background="#ff0000"
android:text="TextView" />
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_bottom="3"
app:layout_left="3"
app:layout_right="4"
app:layout_top="1"
android:background="#00ff00"
android:text="TextView" />
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_bottom="4"
app:layout_left="0"
app:layout_right="3"
app:layout_top="1"
android:background="#0000ff"
android:text="TextView" />
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_bottom="4"
app:layout_left="3"
app:layout_right="4"
app:layout_top="3"
android:background="#ffff00"
android:text="TextView" />
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_bottom="6"
app:layout_left="0"
app:layout_right="1"
app:layout_top="4"
android:background="#ff00ff"
android:text="TextView" />
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_bottom="6"
app:layout_left="1"
app:layout_right="4"
app:layout_top="4"
android:background="#ffffff"
android:text="TextView" />
</com.risch.evertsson.iclib.layout.ICGridLayout>
</ScrollView>
-- Johan Risch
P.S
This is my first long answer, I've tried to do it in a correct way. If I've failed please tell me without flaming :)
D.S
Like this ?
<?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" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.54" >
<Button
android:id="#+id/Button01"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.00"
android:text="Button" />
<Button
android:id="#+id/Button02"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.00"
android:text="Button" />
</LinearLayout>
<Button
android:id="#+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="99dp" >
<Button
android:id="#+id/button1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button" />
<Button
android:id="#+id/button2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Button" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" >
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical" >
<Button
android:id="#+id/button4"
android:layout_width="match_parent"
android:layout_height="152dp"
android:text="Button" />
<Button
android:id="#+id/button5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical" >
<Button
android:id="#+id/button6"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="#+id/button7"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Button" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
As many have said, nested linear layouts seem the only way to win here. Some of the solutions have not used the layout parameters in the most flexible manner. Code below seeks to do that, and in a way that's robust with aspect ratio changes. Details are in the comments.
<?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" >
<!-- First row. -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<!-- Equal weights cause two columns of equal width. -->
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="A" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="B" />
</LinearLayout>
<!-- Second row. -->
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="C" />
<!-- Third row. -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<!-- Equal weights cause two columns of equal width. -->
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="D" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="E" />
</LinearLayout>
<!-- Uneven fourth and fifth rows. -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:baselineAligned="false" >
<!-- Left column. Equal weight with right column gives them equal width. -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical" >
<!--
The use of weights below assigns all extra space to G. There
are other choices. LinearLayout computes sizes along its
axis as given, then divides the remaining extra space using
weights. If a component doesn't have a weight, it keeps
the specified size exactly.
-->
<!-- Fill width of layout and use wrap height (because there's no weight). -->
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="F" />
<!-- Fill width of layout and put all the extra space here. -->
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="G" />
</LinearLayout>
<!-- Right column. Equal weight with left column gives them equal width. -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical" >
<!-- Same as above except top button gets all the extra space. -->
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="H" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="I" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
So here is the solution I promised after one year =)
It basically uses the ViewTreeObserver to get the dimensions of the parent layout and create custom views accordingly. Since this code is one year old ViewTreeObserver might not be the best way to get the dimensions dynamically.
You can find the full source code here:
https://github.com/cdoger/Android_layout
I divided the screen into 8 equal widths and 6 equal heights. Here is a snapshot of how I laid out the views:
final RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.main_layout);
ViewTreeObserver vto = mainLayout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
final int oneUnitWidth = mainLayout.getMeasuredWidth() / 8;
final int oneUnitHeight = mainLayout.getMeasuredHeight() / 6;
/**
* 1
***************************************************************/
final RelativeLayout.LayoutParams otelParams = new RelativeLayout.LayoutParams(
oneUnitWidth * 4, oneUnitHeight);
otelParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
otelParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
// otelParams.setMargins(0, 0, 2, 0);
View1.setLayoutParams(otelParams);
/***************************************************************/
/**
* 2
***************************************************************/
final RelativeLayout.LayoutParams otherParams = new RelativeLayout.LayoutParams(
oneUnitWidth * 4, oneUnitHeight);
otherParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
otherParams.addRule(RelativeLayout.RIGHT_OF, View1.getId());
otherParams.setMargins(2, 0, 0, 0);
View2.setLayoutParams(otherParams);
/***************************************************************/
//... goes on like this
Here is the final screenshot:
Embed your GridLayout in LinearLayout as below and try it worked for me.
<?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="horizontal" >
<GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnCount="2" >
<Button
android:layout_column="0"
android:layout_columnSpan="1"
android:layout_gravity="start|end"
android:layout_row="0"
android:text="ASDFASDF" />
<Button
android:layout_column="1"
android:layout_gravity="start|end"
android:layout_row="0"
android:text="SDAVDFBDFB" />
<Button
android:layout_column="0"
android:layout_columnSpan="2"
android:layout_gravity="fill|center"
android:layout_row="1"
android:text="ASDVADFBFDAFEW" />
<Button
android:layout_column="0"
android:layout_columnSpan="1"
android:layout_gravity="fill|center"
android:layout_row="2"
android:text="FWEA AWFWEA" />
<Button
android:layout_column="1"
android:layout_columnSpan="1"
android:layout_gravity="fill"
android:layout_row="2"
android:text="BERWEfasf" />
<Button
android:layout_width="94dp"
android:layout_column="0"
android:layout_columnSpan="1"
android:layout_gravity="fill|center"
android:layout_row="3"
android:text="SDFVBFAEVSAD" />
<Button
android:layout_column="0"
android:layout_columnSpan="1"
android:layout_gravity="fill|center"
android:layout_row="4"
android:layout_rowSpan="2"
android:text="GVBAERWEFSD" />
<Button
android:layout_column="1"
android:layout_columnSpan="1"
android:layout_gravity="fill|center"
android:layout_row="3"
android:layout_rowSpan="2"
android:text="VSDFAVE SDFASDWA SDFASD" />
<Button
android:layout_column="1"
android:layout_columnSpan="1"
android:layout_gravity="fill|center"
android:layout_row="5"
android:text="FWEWEGAWEFWAE"/>
</GridLayout>
</LinearLayout>