I have a few Button listed vertically and I need all of them to have the same width, but also to display all text inside.
Basically I need width for all of them as a wrapped width of the largest one.
Hope I explained it well.
Now... I already have one layout that is working on my Samsung Galaxy S2 (4.1.2), but on friend's phone - Samsung GT-N7100 (note2) and android 4.4.2 - it is not working - some text is not displayed in the Button.
This is my layout:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="word"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:textSize="30sp"
android:gravity="center"
android:layout_centerHorizontal="true"
android:id="#+id/word"/>
<TextView
android:text="14/36\nM: 1"
android:layout_width="fill_parent"
android:layout_height="80dp"
android:id="#+id/score"
android:layout_toRightOf="#+id/word"
android:gravity="right|center"
android:paddingRight="10dp"/>
<LinearLayout
android:layout_centerInParent="true"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/adapter">
<Button
android:text="1"
android:layout_width="match_parent"
android:layout_height="48dp"
android:id="#+id/opt1"/>
<Button
android:text="2"
android:layout_width="match_parent"
android:layout_height="48dp"
android:id="#+id/opt2" />
<Button
android:text="3"
android:layout_width="match_parent"
android:layout_height="48dp"
android:id="#+id/opt3" />
<Button
android:text="4"
android:layout_width="match_parent"
android:layout_height="48dp"
android:id="#+id/opt4" />
<Button
android:text="5"
android:layout_width="match_parent"
android:layout_height="48dp"
android:id="#+id/opt5" />
</LinearLayout>
<Button
android:text="Next"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_alignParentBottom="true"
android:id="#+id/next"/>
</RelativeLayout>
Try setting android.width="auto"
You can extend the LinearLayout to force all its childs to have the max width:
// LinearLayoutButtonsHolder.java
package github.yaa110.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
public class LinearLayoutButtonsHolder extends LinearLayout {
public LinearLayoutButtonsHolder(Context context) {
super(context);
}
public LinearLayoutButtonsHolder(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LinearLayoutButtonsHolder(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (getChildCount() == 0) return;
getChildAt(getChildCount() - 1).addOnLayoutChangeListener(new OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
v.removeOnLayoutChangeListener(this);
for (int i = 0; i < getChildCount(); i ++) {
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
getChildAt(i).getMeasuredHeight());
getChildAt(i).setLayoutParams(lp);
}
}
});
}
}
Now in the xml file of your layout, use LinearLayoutButtonsHolder rather than LinearLayout. Do not forget to set the android:layout_width of each Button to wrap_content:
<github.yaa110.widget.LinearLayoutButtonsHolder
android:id="#+id/adapter"
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_centerInParent="true"
android:layout_height="wrap_content">
<Button
android:text="Long text for test"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:id="#+id/opt1"/>
<Button
android:text="2"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:id="#+id/opt2" />
<Button
android:text="3"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:id="#+id/opt3" />
<Button
android:text="4"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:id="#+id/opt4" />
<Button
android:text="5"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:id="#+id/opt5" />
</github.yaa110.widget.LinearLayoutButtonsHolder>
use linearlayout like this
<LinearLayout
android:layout_centerInParent="true"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:id="#+id/adapter">
I have done this using XML only (no code) - for two TextViews. But the same technique should work for arbitrary number of buttons as well.
Say we have two TextViews A and B.
Wrap each TextView in a LinearLayout (with only one element inside) - La and Lb.
Set each TextView (A,B) width to 'wrap_content', set background transparent
Set the LinearLayouts (La,Lb) widths to 'match_parent', set background to whatever color/shape you want
Wrap La and Lb inside another Vertical LinearLayout container L, set the width/height of L to be 'wrap_content', height to 'wrap_content'
set padding on each TextView's LinearLayout (La, Lb) to make it look good
set margins on (La, Lb) to create spacing
That should do it.
Note: Make sure the background color/shape for each TextView is set via its background of individual layout container and not on the TextView itself.
I know this question was asked 3 years ago - but I think I saw same/similar questions elsewhere for a solution that involves XML only. So hope this helps someone in the future.
Related
I'm trying to inflate a LinearLayout containing a few different Textviews and a Button into a custom class that extends LinearLayout.
Here is the XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#173BBC"
android:gravity="center_vertical"
android:minWidth="200dp"
android:minHeight="40dp"
android:orientation="horizontal"
android:padding="10dp"
android:visibility="visible">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/textView12"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/compte" />
<TextView
android:id="#+id/textViewCompteT"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TextView" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/textView14"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/valeur" />
<TextView
android:id="#+id/textViewValeurT"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TextView" />
</LinearLayout>
</LinearLayout>
<Button
android:id="#+id/buttonDeleteTransaction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawableTop="#android:drawable/ic_menu_delete"
android:minWidth="48dp"
android:paddingLeft="30dp"
android:paddingTop="10dp"
android:paddingRight="30dp"
android:paddingBottom="0dp"
android:textSize="0sp"
app:cornerRadius="20dp"/>
</LinearLayout>
And here is my class: (please don't take care about the names of the variables, they are bad ;) )
public class TransactionTwo extends LinearLayout {
private Context context;
private LinearLayout container;
private LinearLayout content;
private LayoutParams layoutParams;
private LayoutParams contentLayoutParams;
public TransactionTwo(Context context, Activity parent){
super(context);
activity = (Details) parent;
//here i define my layouts to make them have the fine shape.
layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(10, 10, 10, 10);
contentLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
this.setLayoutParams(layoutParams);
this.setOrientation(LinearLayout.VERTICAL);
this.setBackgroundColor(Color.RED);
container = new LinearLayout(context);
container.setOrientation(LinearLayout.VERTICAL);
container.setLayoutParams(contentLayoutParams);
}
public void createViews(){
//here i try to force the display of the inflated layout (which doesn't appear on screen)
content = (LinearLayout) inflate(context, R.layout.modele_transaction2, container);
content.setVisibility(View.VISIBLE);
content.setLayoutParams(contentLayoutParams);
container.setMinimumHeight(100);
this.addView(container);
//then i find a few textviews and set their text (which works correctly even if i can't see it)...
}
#Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
}
Everything seems to work correctly (at least Android doesn't raise any error), but the only trouble is that I can see the LinearLayout "TransactionTwo" having the size of the LinearLayout that I inflate in it, but I can't see the inflated one... And when I ask for the height of content and container it always answer 0. So it is as if the inflated layout was only giving its size without appearing...
If anyone knows what is wrong in my code, that would be really appreciated because I'm stucked on this issue for a long time now ;)
Thank you!
In fact it might have been a bug of Android Studio, because I made a copy of my java class and it worked this time...
currently I am developing a settings menu in a scrollview. The basic structure looks like the following:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="#+id/scrollview_settings"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="#dimen/paddingSmall">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/transparent_white_settings"
android:paddingTop="#dimen/paddingMedium"
android:paddingBottom="#dimen/paddingMedium">
<ImageView
android:id="#+id/logo"
android:layout_width="68dp"
android:layout_height="wrap_content"
android:src="#drawable/newspaper_logo_color"
android:layout_alignParentRight="true"
android:layout_margin="#dimen/paddingBig"
android:adjustViewBounds="true"/>
</RelativeLayout>
<!-- Layout News Uebersicht -->
<include layout="#layout/separator_line_grey"/>
<de.basecom.noznewsapp.views.FontTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="true"
android:textColor="#color/buttonHoverBackground"
android:textSize="#dimen/sliding_image_kicker_font_size"
android:paddingLeft="#dimen/paddingLarge"
android:paddingTop="#dimen/paddingMedium"
android:paddingBottom="#dimen/paddingMedium"
android:text="#string/news_overview"
android:textScaleX="#dimen/letter_spacing"
android:textStyle="bold"
android:gravity="center_vertical"
android:background="#color/settings_header_color"
android:layout_gravity="center_vertical"/>
<include layout="#layout/separator_line_grey"/>
<!-- News-Overview Issues -->
<LinearLayout
android:id="#+id/issue_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#color/transparent_white_settings">
<de.basecom.noznewsapp.views.NewsScrollListView
android:id="#+id/listview_issues"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
android:divider="#null"
android:dividerHeight="0dp" />
</LinearLayout>
<!-- Layout Einstellungen -->
<de.basecom.noznewsapp.views.FontTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="true"
android:textColor="#color/buttonHoverBackground"
android:textSize="#dimen/sliding_image_kicker_font_size"
android:paddingLeft="#dimen/paddingLarge"
android:paddingTop="#dimen/paddingMedium"
android:paddingBottom="#dimen/paddingMedium"
android:text="#string/settings"
android:textStyle="bold"
android:textScaleX="#dimen/letter_spacing"
android:gravity="center_vertical"
android:background="#color/settings_header_color"
android:layout_gravity="center_vertical"/>
<include layout="#layout/separator_line_grey"/>
<!-- Einstellungs- Werte -->
<LinearLayout
android:id="#+id/settings_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#color/transparent_white_settings">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/paddingLarge">
<de.basecom.noznewsapp.views.FontTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/receive_pushmessages"
android:textAllCaps="true"
android:textScaleX="#dimen/letter_spacing"
android:textSize="#dimen/sliding_image_kicker_font_size"
android:layout_centerVertical="true"
android:textColor="#color/buttonBackground"/>
<Switch
android:id="#+id/receive_pushmessages_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="#string/empty_string"/>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
For the listview I used a custom implementation, to give it a fix height and make it able to scroll within the scrollview (note: I have to use the listview within the scrollview, because I have lots of elements, so that using a linearlayout wouldn't be nice).
public class CustomListView extends ListView {
public CustomListView(Context context) {
super(context);
}
public CustomListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomListView(Context context, AttributeSet attrs,int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Calculate entire height by providing a very large height hint.
// But do not use the highest 2 bits of this integer; those are
// reserved for the MeasureSpec mode.
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
Each item of the listview contains a label and a gridview, which is all shown correctly. But now I want to implement the functionality, that the user can click on the label to show and hide the visibility of the gridview.
But if I click on the label and the gridview is shown, the height of the listview doesn't adapt to the new open element. It always stays at the same height and if I open an element, the elements below are no longer visible. This also even happens, if I call the requestLayout() method of the listview to trigger its onMeasure again.
Anybody got an idea what I am doing wrong?
EDIT: Updated my xml file :)
Finally I was only able to solve this issue by replacing Listview with a LinearLayout and add my items in code to the Layout.
I have the following picture and I want create layout like it, and I need in place of the rectangles to put EditText views. But I can't figure out which is the best way I can achieve this layout, should I make background of the lines or I make relative layout and try align things?
So if someone is experienced with such layouts, please tell how can I do this.
Thanks in advance.
Looking at that image, it looks like you are trying to cram a lot of EditText's into a single screen. That's a pretty unusual layout... unless your application has a very, very specific use case in mind where another layout is inadmissible, I'd advise you to try using one of the more "standard" layouts in Android, as that will likely enhance usability.
However, if you decide that that's really what you need, then I'd take a look at GridLayout, where the rightmost component is expandable and contains a LinearLayout or something like that.
That layout is relatively simple to make, it will be a lot more work to make it work across the large number of Android devices. For example:
<?xml version="1.0" encoding="utf-8"?>
<com.luksprog.ds.views.RelativeLayoutExtension xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="#+id/et10"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:text="X" />
<EditText
android:id="#+id/et9"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_above="#id/et10"
android:layout_marginBottom="25dp"
android:layout_toLeftOf="#id/et10"
android:text="9" />
<EditText
android:id="#+id/et8"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_below="#id/et10"
android:layout_marginTop="25dp"
android:layout_toLeftOf="#id/et10"
android:text="8" />
<EditText
android:id="#+id/et7"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="40dp"
android:layout_toLeftOf="#id/et9"
android:text="7" />
<LinearLayout
android:id="#+id/et65wrapper"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="#id/et7"
android:orientation="vertical"
android:paddingLeft="10dp" >
<EditText
android:id="#+id/et6"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:text="6" />
<EditText
android:id="#+id/et5"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="5" />
</LinearLayout>
<LinearLayout
android:id="#+id/et43wrapper"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="#id/et65wrapper"
android:orientation="vertical"
android:paddingLeft="10dp" >
<EditText
android:id="#+id/et4"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:text="4" />
<EditText
android:id="#+id/et3"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="3" />
</LinearLayout>
<LinearLayout
android:id="#+id/et21wrapper"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="#id/et43wrapper"
android:orientation="vertical"
android:paddingLeft="10dp" >
<EditText
android:id="#+id/et2"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:text="2" />
<EditText
android:id="#+id/et1"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="1" />
</LinearLayout>
</com.luksprog.ds.views.RelativeLayoutExtension>
Where the RelativeLayoutExtension is a class extending the RelativeLayout class like this:
public class RelativeLayoutExtension extends RelativeLayout {
private LinearLayout mFirstLinear;
private LinearLayout mSecondLinear;
private LinearLayout mLastLinear;
private EditText mUpperEditText;
private EditText mLowerEditText;
private Paint mPaint;
public RelativeLayoutExtension(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(2.0f);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
mFirstLinear = (LinearLayout) findViewById(R.id.et21wrapper);
mSecondLinear = (LinearLayout) findViewById(R.id.et43wrapper);
mLastLinear = (LinearLayout) findViewById(R.id.et65wrapper);
mUpperEditText = (EditText) findViewById(R.id.et9);
mLowerEditText = (EditText) findViewById(R.id.et8);
}
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
final int leftFirst = mFirstLinear.getLeft();
final int topFirst = mFirstLinear.getTop();
final int middleFirst = (mFirstLinear.getBottom() - mFirstLinear
.getTop()) / 2;
final int lastRight = mLastLinear.getRight();
canvas.drawLine(leftFirst, topFirst + middleFirst, lastRight, topFirst
+ middleFirst, mPaint);
final int rightFirst = mFirstLinear.getRight();
final int bottomFirst = mFirstLinear.getBottom();
canvas.drawLine(rightFirst, topFirst, rightFirst, bottomFirst, mPaint);
final int rightSecond = mSecondLinear.getRight();
canvas.drawLine(rightSecond, topFirst, rightSecond, bottomFirst, mPaint);
final int leftUpperEdit = mUpperEditText.getLeft();
final int topUpperEdit = mUpperEditText.getTop();
final int middleUpperEdit = (mUpperEditText.getBottom() - mUpperEditText
.getTop()) / 2;
canvas.drawLine(lastRight, topFirst + middleFirst, leftUpperEdit,
topUpperEdit + middleUpperEdit, mPaint);
final int leftLowerEdit = mLowerEditText.getLeft();
final int topLowerEdit = mLowerEditText.getTop();
final int middleLowerEdit = (mLowerEditText.getBottom() - mLowerEditText
.getTop()) / 2;
canvas.drawLine(lastRight, topFirst + middleFirst, leftLowerEdit, topLowerEdit
+ middleLowerEdit, mPaint);
}
}
The lines aren't quite centered, it was just an example.
If you plan to use this layout on a single device for which you know its dimensions the layout will work as you only need to calculate the dimensions once outside of the code. If you plan this as a general layout things will get pretty ugly because you'll need to make a lot of calculations to properly position the views and draw the lines so you may want to rethink your approach. Also I hope that you want to use this layout on large screen devices, because cramming six EditTexts along with spaces on a portrait smartphone will not work pretty well.
You can create it with standard layouts.
The main layout is a FrameLayout.
The background is a image with some lines (or shapes to display lines).
The active layout is a RelativeLayout to show all rectangles.
I have a horizontal LinearLayout containing a TextView followed by a Spinner next to it. This LinearLayout is dynamically inflated multiple times in a fixed vertical LinearLayout contained within a RelativeLayout.
The problem is that since I switched from Theme.light to Theme.holo.light, the last line of the TextView gets cut in half. This happens when the dynamic text is long and spans more than one row.
I have been able to fix this by adding bottom padding to the horizontal LinearLayout containing the TextView and Spinner.
This does not feel like a fix, but more of a hack. Can someone please give me some advice on how to properly fix this?
I have also read some other questions, but none seem to help.
Horizontal Linear layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/textView1"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:text="TextView"/>
<Spinner
android:id="#+id/spinner1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Relative layout where above layout is dynamically inflated at Linear Layout with id ll2_7:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ScrollView
android:id="#+id/scrollView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/relLayoutButtonNext"
android:layout_below="#id/textView1" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp" >
<TextView
android:id="#+id/textView10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="30dp"
android:text="2.7" />
<TextView
android:id="#+id/textView11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_toRightOf="#id/textView10"
android:text="#string/question2_7" />
<LinearLayout
android:id="#+id/ll2_7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView11"
android:layout_below="#+id/textView11"
android:orientation="vertical" android:layout_marginBottom="20dp">
</LinearLayout>
</RelativeLayout>
</ScrollView>
</RelativeLayout>
EDIT:
Here is the complete layout xml for above:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/textView1"
style="#style/question_section_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="#string/question2_header" />
<RelativeLayout
android:id="#+id/relLayoutButtonNext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#color/bottomBar"
android:paddingBottom="3dp"
android:paddingLeft="50dp"
android:paddingRight="50dp"
android:paddingTop="3dp" >
<Button
android:id="#+id/buttonNext"
android:layout_width="180dp"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:onClick="nextStep"
android:text="Next Section"
android:textSize="20sp" />
<Button
android:id="#+id/buttonPrevious"
android:layout_width="180dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:onClick="previousStep"
android:text="Previous Section"
android:textSize="20sp" />
</RelativeLayout>
<ScrollView
android:id="#+id/scrollView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/relLayoutButtonNext"
android:layout_below="#id/textView1" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp" >
<TextView
android:id="#+id/textView10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="30dp"
android:text="2.7" />
<TextView
android:id="#+id/textView11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_toRightOf="#id/textView10"
android:text="#string/question2_7" />
<LinearLayout
android:id="#+id/ll2_7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView11"
android:layout_below="#+id/textView11"
android:orientation="vertical" android:layout_marginBottom="20dp">
</LinearLayout>
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView10"
android:layout_below="#+id/ll2_7"
android:text="2.8" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/ll2_7"
android:layout_toRightOf="#+id/textView10"
android:text="#string/question2_8" android:layout_marginBottom="10dp"/>
<LinearLayout
android:id="#+id/ll2_8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView3"
android:layout_below="#+id/textView3"
android:layout_marginBottom="20dp"
android:orientation="vertical" >
</LinearLayout>
<TextView
android:id="#+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView2"
android:layout_below="#+id/ll2_8"
android:text="2.9" />
<TextView
android:id="#+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/ll2_8"
android:layout_toRightOf="#+id/textView10"
android:text="#string/question2_9" android:layout_marginBottom="10dp"/>
<LinearLayout
android:id="#+id/ll2_9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView5"
android:layout_toRightOf="#+id/textView10"
android:orientation="vertical" android:layout_marginBottom="20dp">
</LinearLayout>
<TextView
android:id="#+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView4"
android:layout_below="#+id/ll2_9"
android:text="2.10" />
<TextView
android:id="#+id/textView7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/ll2_9"
android:layout_toRightOf="#+id/textView10"
android:text="#string/question2_10" android:layout_marginBottom="10dp"/>
<LinearLayout
android:id="#+id/ll2_10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView7"
android:layout_marginBottom="20dp"
android:layout_toRightOf="#+id/textView10"
android:orientation="vertical" >
</LinearLayout>
<TextView
android:id="#+id/textView8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView6"
android:layout_below="#+id/ll2_10"
android:text="2.11" />
<TextView
android:id="#+id/textView9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/ll2_10"
android:layout_toRightOf="#+id/textView10"
android:text="#string/quesiton2_11" android:layout_marginBottom="10dp"/>
<LinearLayout
android:id="#+id/ll2_11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView9"
android:layout_below="#+id/textView9"
android:orientation="vertical" android:layout_marginBottom="20dp">
</LinearLayout>
<TextView
android:id="#+id/textView12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView8"
android:layout_below="#+id/ll2_11"
android:text="2.11.1" />
<TextView
android:id="#+id/textView13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/ll2_11"
android:layout_toRightOf="#+id/textView10"
android:text="#string/question2_11_1" android:layout_marginBottom="10dp"/>
<LinearLayout
android:id="#+id/ll2_11_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView13"
android:layout_toRightOf="#+id/textView10"
android:orientation="vertical" android:layout_marginBottom="20dp">
</LinearLayout>
</RelativeLayout>
</ScrollView>
</RelativeLayout>
I applied a LayoutGravity to the TextView item:
android:layout_gravity="fill"
I've encountered the same cut-off issue as shown at the screenshot. It is caused by the baseline alignment in the horizontal LinearLayout. TextView and Spinner have different baselines due to font size difference. To fix the issue it is needed to disable baseline alignment for the layout by setting:
android:baselineAligned="false"
or in the code:
layout.setBaselineAligned(false);
I had the same problem, and found that simply adding
android:includeFontPadding="false"
the final line of text no longer had its descenders clipped.
I added some dummy space after text by adding
textView.setText(firstString+"\n");
I tried all other solution.But this was the only solution worked for me
I found a different solution by extending TextView and adding a custom Class like this:
public class AdaptingTextView extends TextView {
public AdaptingTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public AdaptingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AdaptingTextView(Context context) {
super(context);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// set fitting lines to prevent cut text
int fittingLines = h / this.getLineHeight();
if (fittingLines > 0) {
this.setLines(fittingLines);
}
}
}
Put the problematic textview inside a framelayout. I think the text view is not calculated correctly because of the sibling view, Spinner.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
android:layout_width="150dp"
android:layout_height="wrap_content">
<TextView
android:id="#+id/textView1"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:text="TextView"/>
</FrameLayout>
<Spinner
android:id="#+id/spinner1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
When this occurs, you should ensure that the TextView is not growing larger than it's container -
If a TextView is set to wrap_content and it's container (or an ancestor container) doesn't leave room for the TextView to grow into it can be occluded.
If that's not the case, it's also possible the onMeasure() of the TextView sometimes doesn't correctly measure the tails of letters, non-latin characters or the effects from text being italic. You can correct for this by setting a global style for your TextView so it will be picked up without needed to change your entire code base:
Ensure that you're application/activities use a custom theme like so:
<style name="Custom" parent="#android:style/Theme.Light">
<item name="android:textViewStyle">#style/Custom.Widget.TextView</item>
</style>
<style name="Custom.Widget.TextView" parent="#android:style/Widget.TextView">
<item name="android:gravity">fill</item>
<item name="android:padding">1sp</item>
</style>
The answer by #Rynadt was really helpful in getting to the above stage. Setting the gravity of the Text inside the View ensures on some devices that occlusion never takes place (The text is correctly fitted inside the view), on others a helping hand with padding of an sp value, ensures that the tails et al are accounted for with a TextSize specific value.
My solution was close to the accepted one, but I had to change it to
android:layout_gravity="fill_vertical"
instead. Otherwise the other rows would have been stretch as well with added line breaks at random places. For example, the biggest row had 4 lines, so another row was changed from
this is a testphrase
to
thi
s is
a testph
rase
try with removing android:paddingBottom="20dp"
from
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp" >
getViewTreeObserver().addOnGlobalLayoutListener does not work in a recycler view. If you're using a recycler, use View.addOnLayoutChangeListener:
I found that the ellipsizing I defined for textView in xml was not always reflected so I programmatically set it before reassigning the text property. This worked for me.
textView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
textView.removeOnLayoutChangeListener(this);
float lineHeight = textView.getLineHeight();
int maxLines = (int) (textView.getHeight() / lineHeight);
if (textView.getLineCount() != maxLines) {
textView.setLines(maxLines);
textView.setEllipsize(TextUtils.TruncateAt.END);
// Re-assign text to ensure ellipsize is performed correctly.
textView.setText(model.getText());
}
}
});
If you have this problem and your TextView is inside a RelativeLayout, try switching the RelativeLayout for a LinearLayout.
That fixed the problem for me
You can use a global layout listener for a TextView in any type of ViewGroup.
final TextView dSTextView = (TextView)findViewById(R.id.annoyingTextView);
dSTextView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
dSTextView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
float lineHeight = dSTextView.getLineHeight();
int maxLines = (int) (dSTextView.getHeight() / lineHeight);
if (dSTextView.getLineCount() != maxLines) {
dSTextView.setLines(maxLines);
}
}
});
You can read more about it here
I know it's so late, but this is work like charm for me.
add this code to your textview
android:ellipsize="marquee"
android:layout_weight="1"
I think there is very little you can do to get this working by altering the layouts. As I have found that some methods work only in some cases. I think it depends on the entire layout hierarchy and is not a one-size-fits-all solution. I have also noticed that it happens especially when you have a different font that you want to set to the TextView.
A sure shot method that I have experimented and tested is that you can set the font attributes in code after the view is inflated. I am assuming that you have a font in the assets/fonts folder that you want to you.
For eg in a Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_view, container, false);
TextView tv = (TextView)view.findViewById(R.id.text_view);
tv.setText("Insert text that needs to be displayed");
AssetManager assetManager = getContext().getAssets();
Typeface typeFace = Typeface.createFromAsset(assetManager, "Fonts/OpenSans-Light.ttf");
tv.setTypeface(typeFace , 0); // 0 is normal font
tv.setPadding(10, 0, 10, 0); // This is not mandatory
}
And in an Activity:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(Resource.Layout.main_activity);
TextView tv = (TextView)this.findViewById(R.id.text_view);
tv.setText("Insert text that needs to be displayed");
AssetManager assetManager = getContext().getAssets();
Typeface typeFace = Typeface.createFromAsset(assetManager, "Fonts/OpenSans-Light.ttf");
tv.setTypeface(typeFace , 0); // 0 is normal font
tv.setPadding(10, 0, 10, 0); // This is not mandatory
}
I have this same problem, and its very annoying.
It only happens with Arabic text.
If you make the label multi-line and adding a \n at the end of your string, it would fix it, but the problem is that there would be a big gap between this label and the object below it, due to the fact that this field now has a new empty line below it.
A custom control can be done to get around that. But overall, this is an annoying bug.
Best workaround for this is to add a dummy View of desired height (i.e. this will add padding itself) at the bottom of your view.
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp" >
<View
android:layout_width="match_parent"
android:layout_height="30dp"/>
</TableRow>
Like in my case I added one more table row at the bottom of the view. Hope this could help someone.
Add padding to the bottom of the text view:
android:paddingBottom="24dp"
I had the same problem and found a handy solution. I get the number of lines of the TextView after rendering and set the height according to the number of lines. Here is the code.
TextView textView = (TextView) layout.findViewById(R.id.textView);
textView.setText(this.text);
textView.post(new Runnable() {
#Override
public void run() {
int linesCount = textView.getLineCount();
textView.setLines(linesCount);
}
});
For me, this solution worked like a charm.
The height and width of my outermost layout was set dynamically, so the TextView contained within got it's text cut even if I set android:maxLines in my xml (for different devices it was behaving differently).
After trying out different methods, finally I got a solution that fixed my issue.
Textview:
public class CustomTextView extends androidx.appcompat.widget.AppCompatTextView {
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomTextView(Context context) {
super(context);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// set fitting lines to prevent cut text
int fittingLines = h / this.getLineHeight();
if (fittingLines > 0) {
this.setLines(fittingLines);
this.setEllipsize(TextUtils.TruncateAt.END);
}
}
}
xml:
<com.myproject.android.customviews.CustomTextView
android:id="#+id/tv_partner_description"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="top"
android:textColor="#color/white"
android:textSize="#dimen/text_small_medium" />
create theme as for particular language like style-ar which cut-off textview:
<style name="EnnodaCustomTextView" parent="Widget.AppCompat.TextView">
<item name="android:paddingTop">1dp</item>
<item name="android:paddingBottom">1dp</item>
</style>
Apply it in you AppTheme to reflect in overall app for padding bottom, as :
<item name="android:textViewStyle">#style/EnnodaCustomTextView</item>
Note : create same style name in default styles.xml with no item tags for padding..(where no need of extra padding )
I finally fixed it!
I try to add String to the TextView in Service and then call scrollTo(), the last line be cut off!
The scrollTo() should be call in "Runnable", like:
private ScrollView mScrollView;
public void scrollToBottom()
{
mScrollView = (ScrollView) findViewById(R.id.debug_textview_scrollview);
mScrollView.post(new Runnable()
{
public void run()
{
mScrollView.fullScroll(View.FOCUS_DOWN);
}
});
}
I think it because in the monent of call scrollTo() in service, the update of TextView is not ready.
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>