I have an ExpandableListView that I'm populating with items. I'd like to have the header (here, "meat") be wider than the list items.
However, ExpandableListView doesn't seem to respect margins/padding defined in XML, and also fails to respect programatically-set padding for the items. It does modify the parent ("meat") but the same code doesn't work for the items.
How can I do this?
Here's the relevant part of my custom adapter:
#Override
public View getGroupView(int position, boolean isExpanded, View view, ViewGroup parent) {
if (view == null) {
LayoutInflater layoutInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = layoutInflater.inflate(R.layout.list_category, null);
}
view.setPadding(10, 0, 10, 0); //RESPECTED
initializeGroupComponents(view, getGroup(position));
return view;
}
#Override
public View getChildView(int position, int expandedPosition, boolean isLastChild, View view, ViewGroup parent) {
if (view == null) {
LayoutInflater layoutInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = layoutInflater.inflate(R.layout.list_ingredient, parent, false);
}
view.setPadding(10, 2, 10, 2); //DOES NOT WORK
initializeChildComponents(view, getChild(position, expandedPosition));
return view;
}
The relevant portions of my XML:
The group:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_categoryContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:orientation="vertical">
The item:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/row"
android:layout_width="match_parent"
android:layout_height="62dp"
android:layout_marginBottom="1dp"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:background="#android:color/white"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="10dp">
Take one extra layout for header and add margin
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_categoryContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginStart="5dp">
//other content
</LinearLayout>
</LinearLayout>
Related
I am creating an Android app that consists mainly of a form. This form needs to have EditText and Spinners side-by-side (for this I chose a LinearLayout). My final goal is to have the text in the Spinner align vertically with the text in the EditText; however, I also want to have padding on the options in the expanded Spinner. This padding messes up the Spinner alignment as it appears in the form.
Here is my code for a custom Spinner list item:
<TextView
android:id="#+id/transportation_spinner_item_textView"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:textColor="#android:color/black"
android:textSize="18dp"/>
Here is my code for the main form:
<LinearLayout
android:id="#+id/linearLayout6"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/divider3"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="100"
android:orientation="vertical">
<TextView
android:id="#+id/ip_minutes_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="#string/ip_minutes"
android:layout_marginTop="4dp"
android:textSize="12sp"/>
<Spinner
android:id="#+id/ip_minutes_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:spinnerMode="dialog"
android:gravity="bottom"/>
</RelativeLayout>
<android.support.design.widget.TextInputLayout
android:id="#+id/ip_charge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="100"
android:layout_gravity="bottom">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="100"
android:editable="false"
android:hint="#string/ip_charge"/>
</android.support.design.widget.TextInputLayout>
</LinearLayout>
And here is an image of how it looks:
Image of alignment with above code
I have been Googling and trying to adjust the padding/margins of different views for hours, so if anyone has any suggestions, that would be great. Thanks!
I'm not sure I fully understand, when you say,
This padding messes up the Spinner alignment as it appears in the
form.
Do you mean the DropDownView? that shows when the Spinner is clicked?
If so, simply create a separate layout for the DropDownView.
In your ArrayAdapter you will have the following methods,
public View getDropDownView(int position, View cnvtView, ViewGroup prnt)
public View getView(int pos, View cnvtView, ViewGroup prnt)
Just have them return two different Views, e.g
#Override
public View getDropDownView(int position, View cnvtView, ViewGroup prnt) {
return getCustomDropDownView(position, cnvtView, prnt);
}
#Override
public View getView(int pos, View cnvtView, ViewGroup prnt) {
return getCustomView(pos, cnvtView, prnt);
}
and
public View getCustomView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
View mySpinner = inflater.inflate(R.layout.custom_spinner, parent, false);
TextView main_text = (TextView) mySpinner.findViewById(R.id.spinner_text);
main_text.setText(spinnerValues[position]);
return mySpinner;
}
public View getCustomDropDownView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
View mySpinner = inflater.inflate(R.layout.custom_dropdown_spinner, parent, false);
TextView main_text = (TextView) mySpinner.findViewById(R.id.spinner_text);
main_text.setText(spinnerValues[position]);
return mySpinner;
}
Is it possible to make an expandable table in Android, that is similar to the expandable list view, but where the child items are in a table/grid format.
For example, something like is here: http://www.coderzheaven.com/2011/04/10/expandable-listview-in-android-using-simpleexpandablelistadapter-a-simple-example/
, but with the child items being a grid of images.
This is how far I've gotten so far (in activity_main.xml using Eclipse Kepler) and am stuck on:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<ExpandableListView
android:id="#+id/expandableListView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
</ExpandableListView>
<ExpandableListView
android:id="#+id/expandableListView2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
</ExpandableListView>
<ExpandableListView
android:id="#+id/expandableListView3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
</ExpandableListView>
</LinearLayout>
With your expandable list view with usage of ExpandableListAdapter you can make your child cells to be TableViews or GridViews or whatever you want inside.
Just inflate view which you want in:
#Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this.context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.your_item_with_grid, null);
}
// get your views from convert view here
return convertView;
}
Here you got ExpandableListAdapter tutorial
I am trying to indent listView row by certain factor. For this, I used view.layout() and view.setX() method but they don't work or result in forceclose. Is there a way to achieve this result. Here is my code:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View newRowView = convertView;
ViewHolder viewHolder;
if(newRowView == null)
{
LayoutInflater inflator = (LayoutInflater) con.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
newRowView = inflator.inflate(R.layout.list_view_images, parent,false);
//newRowView.layout(100*(position/list.size()), 0, 0, 0); // not working
newRowView.setX(100*(position/list.size())); // causing force close
viewHolder = new ViewHolder();
viewHolder.appIcon = (ImageView) newRowView.findViewById(R.id.imageView1);
viewHolder.appName = (TextView) newRowView.findViewById(R.id.textView1);
viewHolder.appName.setText(names.get(position));
newRowView.setTag(viewHolder);
}
list_view_images.xml
<?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" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="#drawable/ic_launcher" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
I am trying to indent the list in semi circular fashion.
What can I do achieve required results?
Regards
Update your getView() method as follows:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View newRowView = convertView;
ViewHolder viewHolder;
if (newRowView == null) {
LayoutInflater inflator = (LayoutInflater) con.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
newRowView = inflator.inflate(R.layout.list_view_images, parent, false);
viewHolder = new ViewHolder();
viewHolder.innerContainer = (LinearLayout) newRowView.findViewById(R.id.innerContainer);
viewHolder.appIcon = (ImageView) newRowView.findViewById(R.id.imageView1);
viewHolder.appName = (TextView) newRowView.findViewById(R.id.textView1);
viewHolder.appName.setText(list.get(position));
newRowView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) newRowView.getTag();
}
float shiftRight = 100 * ((position * 1.0f) / list.size());
viewHolder.innerContainer.setPadding((int) shiftRight, 0, 0, 0);
//...
//...
return newRowView;
}
Update your XML layout as follows:
<?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 xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/innerContainer"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="#drawable/ic_launcher" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
</LinearLayout>
Update your ViewHolder to contain another field as following:
public LinearLayout innerContainer;
Explanation: Basically, we put your original XML layout inside a LinearLayout that acts as an outer container. The we assign padding to the innerContainer (original layout) with respect to the outer layout
I had an ExpandableListView with a CheckedTextView as grouprow View. But I needed to reduce spacing between groups so I've put it inside a LinearLayout. The List does not expand since then, just no reaction on clicks. Any ideas? Code goes below
grouprow.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/holder"
android:clickable="true"
android:orientation="vertical">
<CheckedTextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-13dp"
android:layout_marginBottom="-13dp"
android:text="#string/hello_world"
android:paddingLeft="20dp"
android:textColor="#FFFFFF"
android:textSize="60sp"
android:includeFontPadding="false"
android:textStyle="bold" />
</LinearLayout>
getting the group view:
#Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = minflater.inflate(R.layout.grouprow, null);
}
LinearLayout holder = (LinearLayout) convertView;
CheckedTextView txtGr = (CheckedTextView) holder.findViewById(R.id.textView1);
txtGr.setText(groupItem.get(groupPosition));
txtGr.setChecked(isExpanded);
font = Typeface.createFromAsset(activity.getAssets(),
"uww.otf");
txtGr.setTypeface(font);
return convertView;
}
solved the problem by setting both the LinearLayout and the CheckedTextView to non-clickable
I want to put divider only between parent elements. When i set
android:divider="#drawable/divider" android creates divider between parent elements, but creates divider between child elements too. When i add android:childDivider="#color/transparent" android removes the divider between child elements, but the free space between them remains. Why?
I have tried to android:dividerHeight="0dp" but nothing happened.
At all i want to set divider between parent elements, but i do not want any divider or empty space between child elements.
any ideas how to do that??
In order to remove dividers just from the child views and not between the parents in the expandable list:
add android:childDivider="#00000000" in the ExapandableListView attributes in XML:
<ExpandableListView
android:id="#+id/elv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:childDivider="#00000000" />
Refer this page for more information
Give Divider color and its height (dividers will be visible when groups are collapsed)
<ExpandableListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#color/color_black"
android:dividerHeight="1dp"
android:groupIndicator="#null" />
The trick is to create an extra view for collapse group layout and last child layout.
collapse_group.xml:
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="17sp"/>
<!-- this is the extra view-->
<View
android:layout_width="fill_parent"
android:layout_height="10dp"
android:background="#android:color/transparent"/>
</LinearLayout>
expanded_group.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="17sp"/>
<!-- no extra view-->
</LinearLayout>
And apply the same technique to the child view, for the last child view insert the extra view
What I did was to set the ExpandableListView's divider to 0 and then insert "divider" groups into it's ExpandableListAdapter:
// To get dividers between the groups we add 'divider views' as if they were
// themselves groups.
public int getGroupCount() {
// Actual groups are at even groupPositions, dividers at odd
return (this.data.size() * 2) - 1;
}
public long getGroupId(int groupPosition) {
if(groupPosition % 2 != 0) return R.id.divider;
else return R.id.group;
}
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
if(groupPosition % 2 != 0) {
View divider = convertView;
if(divider == null || divider.getId() != R.id.divider) {
divider = this.inflater.inflate(R.layout.divider, null);
}
return divider;
}
View group = convertView;
if(group == null || group.getId() != R.id.group) {
group = this.inflater.inflate(R.layout.group, null);
}
return group;
}
expListView.setDividerHeight(10);
expListView.setChildDivider(getResources().getDrawable(
android.R.color.white));
If you want to remove child divider only, One simple trick is You can create a drawable with same color as of your child item's background color. Then set it as child divider.
ShapeDrawable sd1 = new ShapeDrawable(new RectShape());
sd1.getPaint().setColor(YOUR CHILD ITEM BACKGROUND COLOR);
mExpListView.setChildDivider(sd1);
Or using xml:
android:childDivider="#color/child_bg_color"
If you want to have divider between parent element of the ExpandableListView (Header) and don't want to have divider between children and parent , which is obviously the most natural case, then you have to do following:
In your parent xml file add one View at the bottom of the layout with divider height and divider color that you need.
Example:
Do same in the child xml file. Add one View at the bottom of the layout with divider height and divider color that you need. Make sure divider color and height are same like in parent xml.
Into your ExpandableListView Adapter method
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent)
manage the state of the View divider like this:
Example:
if(isExpanded){
headerDividerView.setBackgroundColor(ContextCompat.getColor(context,R.color.darker_grey));
}else{
headerDividerView.setBackgroundColor(ContextCompat.getColor(context,android.R.color.transparent));
}
BTW : In my case R.color.darker_grey is background color of the parent
Remove from your ExpandableListView xml all dividers and dividers height. Make ExpandableListView to not have dividers and divider height.
You can use attrs like this :
android:groupIndicator="#null"
android:childIndicator="#null"
android:divider="#null"
android:dividerHeight="0dp"
I solved it by adding two views one to header and other to child item like shown below.
Header.xml
<?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="wrap_content">
<RelativeLayout
android:id="#+id/rl_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/square_box"
android:padding="#dimen/padding_10">
<ImageView
android:id="#+id/expandableIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="#drawable/ic_downarrow" />
</RelativeLayout>
<View
android:id="#+id/view_hidden"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_below="#+id/rl_header"
android:background="#android:color/transparent" />
</RelativeLayout>
child.xml
<?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="wrap_content">
<RelativeLayout
android:id="#+id/rl_childView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/square_box"
android:padding="#dimen/padding_10">
<TextView
android:id="#+id/tv_startDate"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:gravity="left"
android:paddingTop="#dimen/padding_5"
android:paddingBottom="#dimen/padding_5"
android:text="Start Date \nSep. 23, 2019"
android:textSize="#dimen/text_16" />
<ImageView
android:id="#+id/iv_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="#drawable/right_arrow" />
</RelativeLayout>
<View
android:id="#+id/view_hidden"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_below="#+id/rl_childView"
android:background="#android:color/transparent" />
</RelativeLayout>
Now add this code to your Adapter class. The idea is to show/hide the View when group is expanded/collapsed, show on child last item.
#Override
public View getGroupView(int listPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
String listTitle = (String) getGroup(listPosition);
String listCount = "(" + getChildrenCount(listPosition) + ")";
if (convertView == null) {
LayoutInflater layoutInflater = (LayoutInflater)
this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.expandable_header, null);
}
View view_hidden = convertView.findViewById(R.id.view_hidden);
if (isExpanded) {
view_hidden.setVisibility(View.GONE);
} else {
view_hidden.setVisibility(View.VISIBLE);
}
return convertView;
}
#Override
public View getChildView(int listPosition, final int expandedListPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
final Medication medication = (Medication) getChild(listPosition,
expandedListPosition);
if (convertView == null) {
LayoutInflater layoutInflater = (LayoutInflater)
this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.expandable_item, null);
}
View view_hidden = convertView.findViewById(R.id.view_hidden);
if (isLastChild) {
view_hidden.setVisibility(View.VISIBLE);
} else {
view_hidden.setVisibility(View.GONE);
}
return convertView;
}
set like this android:divider="#null" no divider for parents android:divider="2dp" set divider for parents
<ExpandableListView
android:id="#+id/expandable_list"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:divider="2dp"
android:groupIndicator="#drawable/group_indicator" />