I have a listview inside of a viewpager. I set an empty view on the listview. If this listview starts empty, when i add something to it then right or left swipes on the listview won't switch between tabs. If the listview starts with something (not empty) when i set the adapter on it, then i can swipe. If i remove the setEmptyView on the listview, it always works whether it starts with data or without it.
How can i set an empty view and still get the listview to swipe between tabs?
This is how i set the empty view:
mListview.setEmptyView(findViewById(R.id.empty_view));
the empty view is a textview directly below the listview in a linearlayout
the empty view xml:
empty_view.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/empty_list"
android:textColor="#color/lighter_gray"
android:layout_gravity="center"
android:gravity="center"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="#string/no_item"
android:textStyle="italic">
</TextView>
I would suggest removing your empty view from the current layout file, and move it into its own dedicated layout file. Then inflate this new layout in your class when you want to use it as an empty view. The end result would be something like this (not compiled, coding from memory):
final View v = LayoutInflater.from(context).inflate(R.layout.empty_view, null);
mListview.setEmptyView(v);
or maybe
final View v = LayoutInflater.from(context).inflate(R.layout.empty_view, mListview, false);
mListview.setEmptyView(v);
I am working on a simple app, so that the main activity has two fragments that user can swipe to go to. On one of them, I want to have custom list. For example, something like this https://github.com/JakeWharton/SwipeToDismissNOA, where each item in the list can be deleted by swiping. I was able to get a regular list to work inside the ListFragment, but can't get this custom list to work. As I understand, ListFragment needs to have a simple .xml with one , but the one that I want to use, has a bit more stuff in it. Something like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:baselineAligned="false"
android:padding="16dp">
<LinearLayout android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:orientation="vertical">
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:listSeparatorTextViewStyle"
android:text="ListView" />
<ListView
android:id="#android:id/list"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp" />
</LinearLayout>
So when I am trying to getListView() using this .xml, it either returns null or when I am trying to do something like this:
View view = inflater.inflate(R.layout.fragment_section_dummy, null);
ListView ls = (ListView) view.findViewById(android.R.id.list);
It throws this error:
10-15 20:25:28.895: E/AndroidRuntime(8081):
java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView.
Thanks.
For me, is easiest work with my own IDs, so I would change your ListView ID to another one. For my example, I choose android:id="#+id/myList".
In your fragment, in your onCreateView method, try inflating your layout and getting your view by ID.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.yourDummyLayout, container, false);
//You should get your ListView there
ListView yourListView = rootView.findViewById(R.id.myList);
[......]
return rootView;
}
Try with this ;) Good luck !
A quick question:
In ListView I use this code:
list.addHeaderView(headerView);
How to deal with it when working on gridview?
Thanks.
There is no support for header or footer views with GridView, sorry.
There is a quite good implementation of GridView with header support in Google Photos application, as it's OSS code you can use it as is or take it as a reference for your own implementation:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android-apps/4.3_r2.1/com/android/photos/views/HeaderGridView.java
Basic idea is quite simple - WrapperAdapter creates an fake row by increasing number of items by number of columns and then return a header view for the item.
You can use this. The footer appears/hides at the bottom of the grid when you reach/leave the last number of items. It does not actually scroll, but I hardly notice the difference.
In your activity/fragment's onCreate/onCreateView you add an OnScrollListener to the GridView:
....
GridView gridview = (YMAnimatedGridview) v.findViewById(R.id.my_gridview);
gridview.setAdapter(adapter);
final View footerView = mainView
.findViewById(R.id.my_grid_footer_view);
gridview.setOnScrollListener(new GridView.OnScrollListener() {
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (firstVisibleItem + visibleItemCount == totalItemCount) {
// last item in grid is on the screen, show footer:
footerView.setVisibility(View.VISIBLE);
} else if (footerView.getVisibility() != View.GONE) {
// last item in grid not on the screen, hide footer:
footerView.setVisibility(View.GONE);
}
}
#Override
public void onScrollStateChanged(AbsListView view,
int scrollState) {
}
});
Your layout should look something like the below. Notice the layout_weight (and layout_height) parameter in the gridview, it is needed to make the correct space for the footer when it becomes visible.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<GridView
android:id="#+id/my_gridview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:columnWidth="160dp"
android:gravity="center_horizontal"
android:horizontalSpacing="12dp"
android:numColumns="auto_fit"
android:layout_weight="1"
android:stretchMode="columnWidth"
android:verticalSpacing="6dp" />
<TextView
android:id="#+id/my_grid_footer_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_marginBottom="8dp"
android:orientation="horizontal"
android:visibility="gone"
android:text="footer text here" >
</TextView>
</LinearLayout>
Sample code:
GridViewWithHeaderAndFooter gridView = (GridViewWithHeaderAndFooter) v.findViewById(R.id.ly_image_list_grid);
LayoutInflater layoutInflater = LayoutInflater.from(this);
View headerView = layoutInflater.inflate(R.layout.test_header_view, null);
View footerView = layoutInflater.inflate(R.layout.test_footer_view, null);
gridView.addHeaderView(headerView);
gridView.addFooterView(footerView);
Gradle build:
.
compile 'in.srain.cube:grid-view-with-header-footer:1.0.12'
You'd have to use a ListView, then make each row of the list look like it's actually a row of a grid. So if you have a 3 column grid, you'd make a layout for the ListView that looks like 3 columns. You'd then have to modify certain aspects of the Adapter to make it work so that each ListView row actually represents 3 lines of data -- so you know, getCount()/3 type stuff.
How about checking for the "0" index element in your adapter? You can inflate the custom view for the first one.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(view==null){
if(position==0){
// ...inflate header view
}else{
// ...do as usual
Haven't tested it, but should work.
You can use AsymmetricGridView and specify headers/footers with a bigger rowSpan so they would take the entire row.
Why don't you change the appearance of the cells for the first rows? if you know how many columns you have, you know how many items will appear in the header = number of columns.It works for me
You could use this library, http://tonicartos.github.io/StickyGridHeaders/
which allows you to create headers that are sticky (for grouping the list and keeping the header visible for the current group). You can turn off the sticky feature as well.
There is a way to accomplish the desired functionality WITHOUT using a library or anything.
EDIT: Just borrow the HeaderGridView Implementation by google, see Here
You could also customize it for footer. The below suggestion is just too complicated and required more tweaking.
Without going into specific details, all you need to do is this.
1) Subclass GridView
2) override onScrollChanged
3) Calculate the offset everytime it scrolls
4) Set the parentView(view that contains the headerView and gridview) translation y to -Offset.(view.setTranslationY(-offset). Also have an if statement to that once it reaches a certain offset it would stop scrolling.
5) obviously you want to structure this well so your gridview can have a method like attachToGridview(View view). I have a complete implementation of this which works.
See Scroll offset of GridView for help on getting offset since GridView has a bug were the views get recycled.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="vertical">
<com.test.Breadcrumbs android:layout_width="fill_parent" android:layout_height="100dp" />
<GridView
android:id="#+id/grid"
android:numColumns="auto_fit"
android:gravity="center"
android:stretchMode="columnWidth"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp">
</GridView>
</LinearLayout>
and Breadcrumbs:
public class Breadcrumbs extends LinearLayout {
public Breadcrumbs(final Context context, final AttributeSet attrs) {
super(context, attrs);
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layoutView = inflater.inflate(R.layout.breadcrumbs, this, true);
works fine, scroll for grid works as well.
I am attempting to write code that would allow me to have 1-2 views at the top of a listview that are of a different arrangement than the other views in the listview. I decided to try the method of using addHeaderView() for the 1-2 views that will differ in display.
I have two xml layout files, one that defines the view format that most of the listview views will fall under (list_image_checkbox_row.xml) and one for the Header Views (catalog_featured_row.xml). The adapter constructor uses list_image_checkbox_row as its resource in the constructor.
I used a Thread to set the adapter and load the views. I am able to programmatically create views and use addHeaderView to at them to the listview (using the same image resource), but I get errors when I try to use addHeaderView on a view I have inflated from a layout xml file.
handler.post(new Runnable() {
#Override
public void run() {
lv = (ListView)findViewById(R.id.sources_list);
Activity context = BrowseSourceActivity.this;
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.catalog_featured_row, null);
ImageView feat_view = (ImageView) view.findViewById(R.id.image);
feat_view.setImageResource(R.drawable.arrow);
lv.addHeaderView(feat_view);
setListAdapter(array);
}
});
I get a force close error and haven't been able to find anything in logcat (when I was trying to debug yesterday I got a NullPointerException). If I comment out the lv.addHeaderView(feat_view) line, the application does not force close on me. Here is the code for featured_catalog_row.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="70dip"
android:padding="5dip">
<ProgressBar android:id="#+id/spinner"
android:indeterminate="true"
android:layout_width="30dip"
android:layout_height="30dip"
android:layout_centerInParent="true"
/>
<ImageView android:id="#+id/image"
android:gravity="center"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</RelativeLayout>
Any suggestions for how to get the inflater to work?
Perhaps you should store lv in an instance variable instead of looking it up dynamically. Note that both View and Activity have a method called findViewById, and so your results will depend on how your code is organized.
I am using addHeaderView to add a view item to the top of a ListView. I also have a TextView to display a message saying there are no items in the list.
Here is the layout:
<ListView android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="#android:id/empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="#string/list_empty"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium" />
And the Java code:
final ListView listView = getListView();
final View view = getLayoutInflater().inflate(R.layout.list_item_add,
listView, false);
listView.addHeaderView(view, null, true);
When there are items in the ListView then the header is shown but if I delete all items in the list (except the header view) then the header view disappears.
I would like the header view to be visible in the list view whether there are items in the list or not.
Thanks,
Remove the #android:id/empty view from your layout, or override/subclass your adapter to return false from isEmpty()
From my experience (SDK version 10):
Overriding isEmpty() in the adapter makes it work.
Then, it is optional to remove the #android:id/empty view.