Getting child view to match_parent in Android - android

I have a simple linear layout which I'm inflating in an adapter:
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.category_listview_row, parent, false);
} else {
((LinearLayout)convertView).removeAllViews();
}
if (LAYOUT_TYPES.GRID.equals(layoutType)) {
convertView = CategoryFragment.getViewForGridLayout(context, displayArray, position, convertView, listener);
} else {
convertView = CategoryFragment.getViewForListLayout(context, displayArray, position, convertView, listener);
}
return convertView;
}
Here, category_listview_row is the following:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:gravity="top"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
The getViewForGridLayout method programmatically creates one or more views and adds them to convertView.
I would like all the child views to match this parent view in height, however I can't get this to work. This is the outer linear layout of the child views that are added programmatically:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/base_listview_style_one_layout"
android:orientation="horizontal"
android:padding="#dimen/node_default_spacing"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:background="#5ab9c6">
This layout has subviews which are removed according to the actual data to be displayed, so some will be longer than others. However I want them all to be the height of the parent so it doesn't look weird.
This is a screenshot of what I'm seeing:
The first row is ok since both items have a title and a subtext
On the second row, the second item doesn't have a subtext so that view is smaller. However, I'd like it to take the full height of the row so all items in a single row will have the same height.
Any tips? Thanks!

I would advise using a Recyclerview with GridLayoutManager.
If you want certain items spanning multiple columns, you can do so by setting SpanSizeLookup on the GridLayoutManager.
Here is a simple example https://stackoverflow.com/a/26907508/4498224.

Propably your layout params are ignored. Be sure that you are adding child views to your convertView like this:
View view = inflater.inflate( R.layout.item /* resource id */,
convertView /* parent */,
true /*attachToRoot, you dont need to call addView then*/);

Instead of removing the textview, why not just make it invisible or set its color to white to it occupies the space?

Please change your linearlayout height from wrap content to "match_parent".
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:gravity="top"
android:layout_width="match_parent"
android:layout_height="wrap_content" />`

Set the height of parent layout to wrap_content.
Set the height of child view to match-parent.
Try this i hope it will resolve your issue.

#zundi you can use view holder design pattern with recycler view adapter and define which row needs to have two images and which one needs to have one. Its pretty much simpler than doing it with linear layout.
Recycleview show different view types has a pretty decent explanation on how to do this.
And also to answer you question of making
some rows with 2 items and other rows with 1 item
you can use setSpanSizeLookup (GridLayoutManager.SpanSizeLookup spanSizeLookup) method of GridLayoutManager and define it in the activity.
RecycleView's span size gives you more info on how to achieve that.
mLayoutManager.setSpanSizeLookUp(new GridLayoutManager.SpanSizeLookUp() {
#Override
public int getSpanSize(int position) {
if(position == 0)
return 2; //here the view takes up two spaces in a row(header)
else return 1; //here view takes 1 space i.e., 2 views in a total row
} });
In the above example my grid layout manager takes 2 view holders based on different positions and decides if its header or not and populates the data.
Other Solution:
Rather than giving match parent and wrap parent inside your layout give a fixed 'dp' for height. That should make the views look consistent.

#zundi if doing it right way with RecyclerView and LayoutManager which would simplify you life dramatically but have a bit of learning curve doesn't suits you, here is an option that hasn't been mentioned yet:
You can define android:lines=x on TextView which contains subtext.
Just match_parent is not going to work for you because you want LinearLayout to wrap height of its children and its children to match_parent which is a circular dependency

This method can be performed on both Linear Layout or TextView you are using
You have set
android:layout_height="match_parent"
but not the height, so it is simple case
android:layout_height="match_parent"
So, in case even if there will be no value in the string it will still contain the height allotted to it

Related

constraint layout with percentage Guideline dont work in wrap_content

hi guys i want a imageview with the height of 30% of the screen how should i do it? this is my code but its not working when i change the constraintLayout height to match parent it takes all the screen and when i set it to wrap_content now i have nothing in screen
this is my Code:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/guideline1"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/pic" />
<android.support.constraint.Guideline
android:id="#+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.25"/>
</android.support.constraint.ConstraintLayout>
i want to use it on recyclerview when i set the height to match parent this is how become its a lot of empty space below
I assume that the XML you presented is for each of the items in your RecyclerView and that you want each item to take up 1/3 of the height of the RecyclerView. A RecyclerView item is created in onCreateViewHolder() of the adapter and usually just takes into account its own content and inflates to the size it needs to be to hold its content.
You want to impose an external requirement that the RecyclerView item must take up 1/3 of the height of the RecyclerView. There is no way to do this in XML, so you will have to resort to code.
I thought that this would be easy, but it is a little involved, but bear with me.
You will need to determine the height of the RecyclerView so you can compute 1/3 of that value as the height of each item. Unfortunately, as I have discovered, the height of the RecyclerView is not determined until the view holders are created. So, we are in a quandary: We need the height of the RecyclerView to build the view holders, but the view holders must be built to determine the height of the RecyclerView.
To get around this, we will set the height of the RecyclerView to match_parent. This will make the RecyclerView as tall as its parent. We can get the height if the parent before the RecyclerView is fully measured. We will employ a global layout listener to capture the height of the parent. This code should be executed after the RecyclerView (here mRecyclerView) is created and before the adapter is set. In my test suite, I have it defined ion onCreate() of the activity.
mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Remove the listener so we don't get called again.
mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// Capture the height of the parent view group.
int height = ((ViewGroup) mRecyclerView.getParent()).getHeight();
// And let the adapter know the height.
adapter.setItemHeight(height);
// Now that we know the height of the RecyclerView and its items, we
// can set the adapter so the items can be created with the proper height.
mRecyclerView.setAdapter(adapter);
}
});
Add setItemHeight() to the adapter to capture the item height.
private int mItemHeight;
public void setItemHeight(int parentHeight) {
mItemHeight = parentHeight / 3;
}
Finally, we can use the item height to create the items:
#Override
public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
view.getLayoutParams().height = mItemHeight;
return new ItemHolder(view);
}
You may need to adjust the item's height if the RecyclerView has padding, margins or decorations.

ExpandableListView, how to set the child height?

I'm trying to set the ExpandableListView item (ViewGroup) height. Can it be set via xml (I don't need the divider height):
<ExpandableListView
android:id="#+id/lvExp"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
or it should be used this method, by manipulating the convertView:
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) { ... }
Thanks in advance.
ListView child views can be different heights, so we don't set a one-size-fits all height in the ListView's xml. Rather you can set a specific height in each of the different convertView xml's that you are inflating.
Are you trying to set the height of the group row item in the listview? Also the ViewGroup would be your ExpandableListView and all of its groups and group children row items.
Or are you asking to set the height of the child items in the expandable list view?
The group item and its children in the listview are the same as any other listview row item.
You can just simply provide fixed height in row layout XML:
android:layout_height="25dp"
Or you could use ViewGroup.LayoutParams
http://developer.android.com/reference/android/view/ViewGroup.LayoutParams.html
Question is a bit old, but someone may be useful. As others said, height is not strict value (it changes according to its content). If you want to generally make more space between items (whether it is group or child), you can set padding to corresponding layouts.
This can be done either in XML layout or programmatically in list adapter.

Header View height in a ListView

I'm working with a ListView that is part of an ListFragment. I want to add a header with a specific/custom height but it does not matter what I put in the height of the header view, always it has the same height. Is possible to modify the header view height of a ListView?
Below the code I use:
header.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp" />
ListFragment
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
TextView fakeHeader = (TextView)getActivity().getLayoutInflater().inflate(R.layout.header, null);
getListView().addHeaderView(fakeHeader);
}
When you pass in null as the second parameter to inflate(), you are saying there is no parent associated with the view. This has the unfortunate side effect where any layout_ attribute you use is ignored as layout_ parameters affect how the parent lays out the child view rather than directly affect the child (like other views): this pro-tip godes into more details on layout_ attributes.
You can use inflate(R.layout.header, getListView(), false) to pass in the ListView which will eventually the parent of your header view (note the false says to not add the view directly - ListView will do this automatically for you).

ListView / GridView: Setting child layout properly

I want to create a ListView (same question is relevant for a GridView) where the items have very specific LayoutParams. Take this example where I want each row to be a LinearLayout with a height of 100dp:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="100dp">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/pd_textview"
android:gravity="center_vertical"/>
</LinearLayout>
When I use this XML layout with a standard BaseAdapter implementation of getView() that inflates the views none of the LayoutParams for my LinearLayout get applied (each row simply wraps around the size of the text in the TextView):
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Inflate view if necessary
if (convertView == null) {
convertView = ((Activity) mContext).getLayoutInflater().inflate(ID_LAYOUT, null, false);
}
// Return the view
return convertView;
}
Fishing around in the appropriate section of the Android documentation, it says the following about getView() which explains the current behaviour:
Get a View that displays the data at the specified position in the
data set. You can either create a View manually or inflate it from an
XML layout file. When the View is inflated, the parent View (GridView,
ListView...) will apply default layout parameters unless you use
inflate(int, android.view.ViewGroup, boolean) to specify a root view
and to prevent attachment to the root.
My question is simply, how should I actually be doing this? The suggestion of using a root view with the desired LayoutParams seems convoluted given that the LayoutParams I want to inflate the view with are in the view that I'm trying to inflate (yes I could inflate a static view and leave it as a member of the class to reference against... but that seems silly). The other option would be to only define the contents of the row item in XML and manually create the container and its LayoutParams every time?
Is there a 'correct' way (i.e. not a wasteful hack) that I'm missing to simply create items with the LayoutParams defined in the XML?
I'd have preferred to put this in a comment, but I don't have the 50 reputation needed to do that...
There is detailed explanation of the issue here:
http://www.doubleencore.com/2013/05/layout-inflation-as-intended/
The main point is this:
"The problem with this is android:layout_xxx attributes are always be evaluated in the context of the parent view. As a result, without any known parent, all LayoutParams you declared on the root element of your XML tree will just get thrown away [,...]"
So, indeed, the solution is:
convertView = ((Activity) mContext).getLayoutInflater().inflate(ID_LAYOUT, parent, false);

Distribute a group of buttons evenly inside an Android Layout

I have 12 buttons and they must be distributed evenly across the horizontal and vertical axis of a Layout. I cannot use GridLayout. This is how it should look:
Also, I don't want to get message about performance issues due to wrong use of the weight property. Right now I am trying to do it with a RelativeLayout, setting each buttons position in relation to the others but maybe there is a simpler/easier/more recommended way.
UPDATE
So, I decided to use a GridView and this is my code right now:
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/menuGrid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="32dp"
android:numColumns="3"
android:verticalSpacing="5dp"
android:horizontalSpacing="5dp"
android:stretchMode="spacingWidthUniform"
android:gravity="fill" />
My adapter class is this:
public class GridAdapter extends BaseAdapter {
// Different methods ...
// Images for the buttons
private Integer[] mThumbIds = {
R.drawable.btn_1, R.drawable.btn_2, R.drawable.btn_3,
R.drawable.btn_4, R.drawable.btn_5, R.drawable.btn_6,
R.drawable.btn_7, R.drawable.btn_8, R.drawable.btn_9,
R.drawable.btn_10, R.drawable.btn_11, R.drawable.btn_12
};
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageButton imageButton;
if (convertView == null) {
imageButton = new ImageButton(mContext);
imageButton.setLayoutParams(new GridView.LayoutParams(48, 48));
imageButton.setScaleType(ImageButton.ScaleType.CENTER_CROP);
} else {
imageButton = (ImageButton) convertView;
}
imageButton.setImageResource(mThumbIds[position]);
return imageButton;
}
}
In my main activity I am setting the adapter like this (they are centred and don't occupy the entire space):
GridView gridview = (GridView) v.findViewById(R.id.menuGrid);
gridview.setAdapter(new GridAdapter(this));
but the buttons are displayed like this (centered and small, instead of occupying the entire area):
I cannot use GridLayout
so use GridView >>> LINK <<<, available since API 1. Works just like a ListView (minus footer n header) and with a numColumns parameter
You can try:
GridLayout, which is available back to API Level 7 via a backport from the Android Support package's gridlayout-v7 library project
TableLayout, using android:stretchColumns to allocate space to all columns... but this will only work if the cells are themselves the same width
Nested LinearLayouts and android:layout_weight, as the concerns about performance may or may not be an issue for you (e.g., this is a single activity or fragment layout, not a row in a ListView)
And, you can always implement your own ViewGroup with your own business rules for sizing and positioning your child widgets.
What you are presently trying -- RelativeLayout -- seems unlikely to work in a fashion that will adapt to different screen sizes well.

Categories

Resources