I am trying to implement a screen like this:
The view could be scrolled horizontally and inside each of them they could be scrolled vertically. The number of items in each is arbitrary.
Currently I am thinking of implementing it using a recyclerview within a recyclerview but is there an easier way to do this?
You can use a scrollView and programatically add views in this scrollview. But i recommended recyclerview.
int countOfViews = 20;
LinearLayout root= findViewById(R.id.scrollViewRoot);
for(int i = 0; i < countOfViews; i++) {
View child = getLayoutInflater().inflate(R.layout.item_test, null);
root.addView(child);
}
XML: item_test.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/scrollViewRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"></LinearLayout>
</ScrollView>
I want to allow my ListView to be wrapped to its content on its width and making it aligning to the parent centre.
This is what a normal ListView is giving me
This is almost what i want to achieve, only that i want the ListView to wrap by the longest test in the ListView. Currently this is achieved by declaring the dp which is something I would like to avoid if possible
Some codes for first image:
<ListView
android:id="#+id/lst_test"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content" >
</ListView>
Some codes for second image:
<ListView
android:id="#+id/lst_test"
android:layout_width="200dp"
android:layout_height="wrap_content" >
</ListView>
Do I have to use custom adapter for this or I can stick with the current one? If I would need to use custom adapter, how do i go about doing this?
You don't need to create custom adapter. Here is an example which can help you.
public class MainActivity extends Activity {
HashMap <String, CheckBox> options = new HashMap<String, CheckBox>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView list_view = (ListView) findViewById(R.id.listView1);
ArrayList<String> str = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
str.add("Example " + i);
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_layout, R.id.textView1, str);
list_view.setAdapter(adapter);
}
}
Above I have created an activity in which i am getting listview and setting data using ArrayAdapter.
I have created two layouts :
First layout: Contains listview.
Second layout: Contains textview which need to display.
Main logic to align data at center of Listview is you need to set gravity of textview as center.
You can manage second layout according to your needs.
Here is my first XML layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" >
</ListView>
</RelativeLayout>
Here is my second layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/RelativeLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:gravity="center"
android:text="TextView" />
</RelativeLayout>
If you are still facing any problem then you can ask. If you need more flexibility then you can create custom adapter by inheriting ArrayAdapter class.
Here is an example of custom adapter: How do I link a checkbox for every contact in populated listview?
Hope it will help you.
I can't seem to find a way to make a layout that contains a ListView that show the entire list of my contacts (its a long list), with 2 buttons one next to the other below the list.
its freaking me out, nothing i do seems to work. i searched some related quiestions and found this one: Android Layout with ListView and Buttons
but none of the alternative solutions over there is working for me.
when i look at the graphical presntation (of eclipse) it looks fine, but when i run it on my device i can only see the list of contacts. the listView overlaps the buttons.
I am using a simpleList that render on another layout that represent a row. i'm starting to suspect something i do programtically ruins it, because i ran over my java code and found no mention of the activity_contact_list that i was talking about. only connection to the row layout.
so i got this activity_contact_list.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/contact_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_alignParentTop="true" >
</ListView>
<LinearLayout
android:id="#+id/buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_weight="1.0"
android:orientation="horizontal" >
<Button
android:id="#+id/action_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Cancle" />
<Button
android:id="#+id/action_add"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Add" />
</LinearLayout>
</LinearLayout>
this is after many tries such as: using RelativeLayout instead of the LinearLayout, puting the ListView's code below the LinearLayout of the buttons, and many more..
and here is the code of the activity: ContactList.java:
public class ContactList extends ListActivity{
//some global variables for late use.
public Model model;
SimpleAdapter adapter;
List<Map<String, String>> data; /* data is a list of Map */
String[] from = {"name","phone"}; /* names of the columns */ //TODO - add date!
int[] to = {R.id.name, R.id.number};
List<Contact> contacts; /* list of contacts */
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_contact_list);
// Set up the action bar.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayHomeAsUpEnabled(true);
model = Model.getInstance(this);
data = new ArrayList<Map<String, String>>();
contacts = fillContactsList();
fill_data();
adapter = new SimpleAdapter(this, data, R.layout.contact_list_row, from, to);
setListAdapter(adapter);
}
i commented the setContentView line cause it doesnt compile otherway...
As is said. the list works perfactly. but it overlaps the buttons at the bottom of the activity. any idea? i'm sure its something silly i'm missing..
thanks in advance!
Did you try to use Relative Layout ?
Change Linear Layout to Relative Layout that's all.
As Linear Layout Doesn't support align parent..
Edited
set List Height to mach parent.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/contact_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/list"
android:layout_below="#+id/buttons"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
<LinearLayout
android:id="#+id/buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="2" >
<Button
android:id="#+id/action_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Cancle" />
<Button
android:id="#+id/action_add"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Add" />
</LinearLayout>
How long is your ListView. Maybe it is longer than your screen and is the LinearLayout with buttons shown outside your screen.
What happens when you rearrange with the buttons above the ListView.
EDIT:
I think you have to set a Max-size in your ListView. Maybe you can try something like this in your java-code, but I don't know if it is scrollable then...
ListView listView = (ListView) findViewById(R.id.listView):
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) listView .getLayoutParams();
params.height = 200; // or something bigger / smaller
listView .setLayoutParams(params);
Is it possible to have a margin/padding for the ListView without having the margin applied to the header? I want my ListView to be like the Google Now layout. I've got everything working except for this little problem.
Question: Is it possible to not have layout parameters of the ListView apply to its header?
EDIT1:More info
The purple view is the header to the listView.
I have tried adding margin to the list item layout.This doesnt work either.
All i need is a way to apply margin to the listview so that it doesnt apply the margin to the header in the listView.
EDIT2:
My layouts
header.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:orientation="vertical" >
<View
android:layout_width="match_parent"
android:layout_height="#dimen/top_height"
android:background="#color/top_item" />
<View
android:id="#+id/placeholder"
android:layout_width="match_parent"
android:layout_height="#dimen/sticky_height"
android:layout_gravity="bottom" />
</FrameLayout>
root_list.xml
<LinearLayout>
<com.test.CustomListView
android:id="#android:id/list"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_height="wrap_content" /></LinearLayout>
list_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/card_background"
android:orientation="vertical" >
<TextView
android:id="#+id/textview_note"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/textview_note_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"/></LinearLayout>
I've removed uselsess layout properties here due to length of this post.
After much digging around i found that its is not posssible to decouple the listView layout params from its headers and the header is part of listView. So in order to get the desirred margin effect, After much looking around I found out that adding margin to your root of the layout in the list view item didnt work. So I added another dummy LinearLayout inside the existing root LinearLayout(a nested LinearLayout) and added the children inside the nested layout.Now setting margin to the inner layout gives the desired effect.
Code:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="16dp"
android:layout_marginLeft="16dp"
android:background="#drawable/list_selector"
android:orientation="vertical" >
<TextView
android:id="#+id/textview_note"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/textview_note_date"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
In your header part, add the following tag:
android:layout_alignParentLeft="true"
this will solve your problem.
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, attrs, false);
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
...
return result;
this is the code of LayoutInflater,as you can see ,if you add a root,it's not null,generated the layoutParams from root.
and then if the thrid param is false,there is only make temp.setLayoutParams(params) which params is generated by root!! and the temp is as return....
if attachToRoot is true,root will execute root.addView(temp, params),and then the root is as return..
if you just do LayoutInflater.from(this).inflate(R.layout.popup_choose_type, null);,and if you had set some attribute as paddingBottom,it will surprised you that is will not work!!because of loss LayoutParams!
As for how to solve it,you can see
here
you can do it by give margin in listview's layout file then you will get it the output.
I've got a view that is effectively is a button. Here is its XML layout (add_new.xml)
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:id="#+id/buttonNew"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/bText"
android:onClick="addNew"/>
</LinearLayout>
When I set its visibility to GONE like this
v = getActivity().getLayoutInflater().inflate(R.layout.add_new, null);
v.setVisibility(View.GONE);
it disappears but still occupies space. Like this:
This button is a header in the ListView, which is defined by this xml:
<?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:id="#+id/porno" >
<ImageView
android:id="#+id/icon"
android:layout_width="30dp"
android:layout_height="40dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="10dp"
android:layout_marginTop="4dp"
android:src="#drawable/ic_launcher">
</ImageView>
<TextView
android:id="#+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#+id/label"
android:textSize="20dp" >
</TextView>
</LinearLayout>
And I dont want it to occupy an additional list item when its visibility is set to GONE. As it is stated in the documentation.
GONE - This view is invisible, and it doesn't take any space for
layout purposes.
Any ideas on how to make it NOT occupy space?
Thanks,
Dennis xx
P.S. My listview is inside of a FoldersFragment ListFragmentand here is the xml of my MainActivity where FoldersFragment is presented
<?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" >
<fragment
android:id="#+id/foldersFragment"
android:layout_width="200dip"
android:layout_height="match_parent"
class="com.example.fragments.FoldersFragment" >
</fragment>
<fragment
android:id="#+id/detailFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.example.fragments.DetailFragment" >
</fragment>
</LinearLayout>
This is an Android bug in my opinion, we just fix this issue doing this:
<FrameLayout android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout android:id="#+id/layout_to_hide"
android:layout_width="match_parent"
android:layout_height="wrap_content">
//Put here your views
</LinearLayout>
</FrameLayout>
Just hide LinearLayout with id LAYOUT_TO_HIDE with Visible.GONE and then root FrameLayout will collapse its height giving you a "hidden" with non-blank-space header.
set layout_width and layout_height to 0 where you want to hide item, by doing this
//if item's parent layout is LinearLayout, change according to your item xml
holder.itemView.setLayoutParams(new LinearLayout.LayoutParams(0,0));
All replies in this thread are suggesting a new wrapper view, which comes at a cost. The correct way of hiding a view completely is to set margins to 0 while setting visibility to GONE. In this code sample, cardView is the view I am trying to hide. The direct parent of cardView is RecyclerView, that's why we are using RecyclerView.LayoutParams - remember to replace with the right layout params.
if (cardView.getVisibility() != GONE) {
cardView.setVisibility(GONE);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) cardView.getLayoutParams();
layoutParams.setMargins(0, 0, 0, 0);
cardView.setLayoutParams(layoutParams);
}
If this is stil needed, there is a great way to deal with it:
parentView.removeView(childView);
here an example:
final WhatEverLayout parentView, childView;
parentView = (WhatEverLayout)findViewById(R.id.parentView_xml);
childView =(WhatEverLayout)findViewById(R.id.childView_xml);
parentView.removeView(childView);
What you can do is set an if statement, whenever the condition to set the visibility to "GONE", set the view as wrap content and your space will be free, I did it and it worked for a seekbar
This is my solution. Create a new layout file with name "special.xml", copy the code to the file.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
</LinearLayout>
Use condition to inflate the empty layout inside the newview. Don't Use the view.setVisibility(View.GONE);.
if(true){
view=mInflater.inflate ( R.layout.special,parent, false );
}else{
view=mInflater.inflate(R.layout.normal,parent,false);
// The view that you want to be visible
}
header_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/mHeaderView"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/mNoHelpLayout"
android:layout_width="match_parent"
android:layout_height="176dip"
android:background="#ffffffff"
android:gravity="center"
/>
</LinearLayout>
</LinearLayout>
java code:
LayoutInflater mInflater =(LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View outerView = mInflater.inflate(R.layout.header_layout, null);
mHeaderView = (LinearLayout) outerView.findViewById(R.id.mHeaderView);
use mHeaderView.setVisiable() to control visiable not the outerView.setVisiable().
it works for me.
If you want to show itemView
if (ItemBean.isShow())
{
holder.itemView.setVisibility(View.VISIBLE);
holder.itemView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
} else
{
holder.itemView.setLayoutParams(new LinearLayout.LayoutParams(0, 0));
holder.itemView.setVisibility(View.GONE);
}
You can use :
viewToHide?.postDelayed({ viewToHide?.visibility = View.GONE }, durationInMillis)
For me, it worked if I did the showing/hiding on the next run loop.
parentView.post {
childViewToHide.visibility = View.GONE
}
I had similar issue when using TransitionManager.beginDelayedTransition(), in the Layout Inspector tool I see that the view is Gone, but it still taking space, I think it is bug in Android, a workaround is to execute the visibility block with View.post(Runnable action)
In my case I was using an animation and in my anim, I had the flag
android:fillAfter="true"
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<translate
android:duration="300"
android:fromYDelta="100%"
android:toYDelta="0%" />
<alpha
android:duration="150"
android:fromAlpha="0"
android:toAlpha="1" />
</set>
This caused the view to be set as invisible even when it was being set to GONE.
After removing android:fillAfter="true" I had no more issues and the view was then properly being set to GONE.
Simplest way is to force the parent view to remeasure its own height after children visibility changed.
Try something like this :
parentView.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
in this case, parent view is a LinearLayout.
A generic and easy solution is to avoid all thuse heck of code:
You need to add a Container Layout or a Parent Layout over your set of views that you want to hide. It can be anything like CardView or FrameLayout or etc.
Just it has to be a parent for that view that you want to hide. And you wont get all those white spaces. Coz it will consider the entire container to hide instead of considering individual views to HIDE thus, avoiding the white spaces.
Setting view padding and margins to 0 and then set view visibility to gone solved my problem.
I don't think this is a bug.. Just use GONE to make the empty space disappear.
CSS does the same thing. Try display: block vs visibility: hidden.