Android tabs containing list scrolling to top - android

I am building an android application containing 4 tabs, each containing a fragment attached to cursor adapter. Each fragment contains a list of items.If I scrolled a lot down in any list, I have to scroll a lot back to get to the top.I want the it to behave like this: when I click on the current tab icon, it will automatically scroll back to top. How can I implement this functionality?
edit 1:
this is how the it is implemented:-
public class OutboxFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
OutboxListAdapter mAdapter;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAdapter = new OutboxListAdapter(getActivity(),R.layout.outbox_list_item, null, 0);
setListAdapter(mAdapter);
getLoaderManager().initLoader(0, null, this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_outbox, container, false);
return view;
}

On tab changed you can refresh your list view:
MyAdapter myAdapter = new MyAdapter(mContext, items);
mListView.setAdapter(myAdapter);
mListView.setSelection(0);
Instead of setting a new adapter (which causes ListView to reset its state), simply update the content of the adapter already set on the ListView.
You can create a refill() method to your adapter:
public void refill(List<EventLog> events) {
mEvents.clear();
mEvents.addAll(events);
notifyDataSetChanged();
}
And call it onTabChanged:
if (mListView.getAdapter() == null) {
MyAdapter myAdapter = new MyAdapter(mContext, items);
mListView.setAdapter(myAdapter);
} else {
((MyAdapter)mListView.getAdapter()).refill(items);
}

based on your problem you need to scroll the fragment list to the top. you can do this by calling following function:
getListView().smoothScrollToPosition(0);
which getlistView returns your fragment ListView;

Related

Random Out Of Bounds after removing item from static list used by multiple fragments

I have a fragment with a viewpager with adapter extending FragmentStatePagerAdapter with three slidable fragments inside. the main fragment has a static list of data, and three sub-fragments references and show the same list (don't ask why). The list item can be removed by a button inside the row layout or by clicking clear-all button after the list in each of those three fragments.
My problem is that after removing one or all the items with the buttons, sometimes i get an instant index out of bounds exception (no application code in stack trace, to find where the exception is coming from) or randomly sometimes removal work, but fragments nearby display old data with the extra item, and clicking to remove it ofcourse throws out of bounds exception, because after some debugging I can see that size of list passed to adapter to recreate the nearby fragment is lower by one (removal is successful) so I believe the list is not notified/invalidated correctly. Any help, since stacktrace can't help?
Btw I'm using FragmentStatePagerAdapter.POSITION_NONE to recreate the fragments with new data on each swipe, notifyDataSetChanged to notify the adapter of changed data, and invalidate() the listview in onViewCreated(), but they don't help.
relevant code:
Main Fragment
public class MainFragment extends BaseFragment<CategoryTreeItem> {
public static List<Map.Entry<EventTreeItem, String>> betList = new ArrayList<>();
...
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ViewPager mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
mViewPager.setAdapter(new MyPagerAdapter(getChildFragmentManager()));
SlidingTabLayout mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
mSlidingTabLayout.setViewPager(mViewPager);
}
}
class MyPagerAdapter extends FragmentStatePagerAdapter {
private List<String> items;
public MyPagerAdapter(FragmentManager fm) {
super(fm);
items = getResources().getStringArray(R.array.three_categories);
}
#Override
public Fragment getItem(int i) {
Fragment fragment;
switch (i) {
case 0:
fragment = new FirstFragment();
return fragment;
case 1:
fragment = new SecondFragment();
return fragment;
case 2:
fragment = new ThirdFragment();
return fragment;
default:
return null;
}
}
...
#Override
public int getItemPosition(Object object) {
return FragmentStatePagerAdapter.POSITION_NONE;
}
}
Three fragments (they are needed since the layout and functionality is a bit different)
public class First/Second/ThirdFragment extends BaseListFragment<ArrayList<EventTreeItem>> {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
MyListAdapter adapter = new MyListdapter(getActivity(), R.layout.item_first/second/thirdfragment, MainFragment.betList);
getListView().setItemsCanFocus(true);
View footerView = getLayoutInflater(savedInstanceState).inflate(R.layout.include_first/second/third_footer, getListView(), false);
getListView().addFooterView(footerView);
adapter.notifyDataSetChanged();
setListAdapter(adapter);
getListView().invalidate();
//handles REMOVE ALL button for all fragments footer button
Helper.setUpClearOption(footerView, adapter);
}
}
MyListAdapter
#CompileStatic
public class MyListAdapter extends ArrayAdapter<Map.Entry<EventTreeItem,String>> {
private int mResourceId;
private List<Map.Entry<EventTreeItem,String>> mObjects;
public MyListAdapter(Context context, int resource, List<Map.Entry<EventTreeItem,String>> objects) {
super(context, resource, objects);
mResourceId = resource;
mObjects = objects;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
view = LayoutInflater.from(getContext()).inflate(mResourceId, parent, false);
}
//------setting a lot of text for textViews
// .....
//------
ImageView ivRemove = (ImageView) view.findViewById(R.id.ivRemove);
ivRemove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Tried removing directly from adapter, not helping
// MyListAdapter.this.remove(mObjects.get(position));
MainFragment.betList.remove(position);
MyListAdapter.this.notifyDataSetChanged();
}
});
return view;
}
}
Remove All helper method (also returning instant OOB or not notifying neighbor fragments)
public static void setUpClearOption(View view, final ArrayAdapter adapter) {
ImageView ivRemoveAll = (ImageView) view.findViewById(R.id.ivRemoveAll);
ivRemoveAll.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
adapter.clear();
adapter.notifyDataSetChanged();
}
});
}
So any help is much appreciated!
I managed to fix My problem by creating three listadapters for each of my fragments (static adapters instantiaiting with null value ) and in onClick I check each of those three adapters if they are not null (since adapters are null until after onViewCreated, and it is called only when the current fragment is a neighbor). All three adapters use the same data.

Some1 know why my listview data is not changing?

My listview gets filled on the start but after i cant find a way to make changes
pls see the code bellow
public class myFragment extends android.support.v4.app.Fragment
{
ListView list;
ArrayList<String> restorants=new ArrayList<String>();
Manager m=new Manager();
ArrayAdapter<String> adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_, container, false);
list=(ListView) rootView.findViewById(R.id.myList);
for(Restorant r : m.getResByCity("nyc"))
{
restorants.add(r.getName());
}
adapter=new ArrayAdapter<String>(getActivity(), R.layout.item_list, R.id.restorantItem,restorants);
list.setAdapter(adapter);
return rootView;
}
public void makeChange(String s)
{
restorants.remove(0);
((ArrayAdapter)list.getAdapter()).notifyDataSetChanged();
}
}
While calling the method makeChange() i have checked that the restorants items are removing so that there is no problem with calling the method
makeChange() is called from my mainActivity that contains viewpager where this fragment is contained in the viewpager.
you need to remove the element from the dataset you provided to the adapter,
adapter.remove(s)
Here you can find the documentation

Why is my ListView not showing the new data?

my problem is, that I have a ListView and a ArrayAdapter. Now I create the adapter like this:
items = OtherClass.DataSet1;
adapter = new MyArrayAdapter(getActivity(), R.layout.mein_listitem, items);
then I want to change the items e.g:
items = OtherClass.DataSet2;
adapter.notifyDataSetChanged();
But the result is, that I still see the DataSet1 items in my ListView and I dont know why.
I have the following whole code:
public class PlaceholderFragment extends Fragment implements ActionBar.TabListener {
ArrayList<Item> items;
MyArrayAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
items = OtherClass.DataSet1;
adapter = new MyArrayAdapter(getActivity(), R.layout.mein_listitem, items);
{...}
}
#Override
public void onTabSelected(Tab arg0, FragmentTransaction arg1) {
if (arg0.getText().equals(getText(R.string.foo))) {
items = OtherClass.DataSet1;
adapter.notifyDataSetChanged();
} else {
items = OtherClass.DataSet2;
adapter.notifyDataSetChanged();
}
}
}
public class Item {
public Item(String foo1) {
super();
Foo1 = foo1;
}
public String Foo1;
}
You have to add your items on your ArrayAdapter object via the .add() or .addAll() methods. This will actually append the objects you've provided as parameters to the dataset already showing up.
adapter.add(...);
adapter.addAll(...);
And (as you done), don't forget always calling .notifyDataSetChanged() on your adapter after adding items to it.

Android, empty listview afrer back from other fragment

Hy, i've got list view in my fragment. I am replacing this listview fragment with my other fragment but when i want back to my list, it's empty. I thought i could restore my list items but i don't know how. I Assumed that accord with Fragment lifecycle my adapter will be reusable but looks it's not. Here is my code:
public class ThreadListFragment extends Fragment implements FragmentConnectionStatus, ListFragment, OnClickListener, OnItemClickListener{
private ListView ListView;
private PilotController Activity;
private Button ButtonStartNewThread;
private boolean Paused;
private ThreadInfoAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
/**
* Inflate the layout for this fragment
*/
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.threads_list_fragment, container, false);
System.out.println(this.Paused);
if(this.Paused == false){
this.ListView = (ListView) view.findViewById(R.id.listViewActiveThreads);
ArrayList<Guid> strs = new ArrayList<Guid>();
adapter = new ThreadInfoAdapter(view.getContext(), strs, this);
}
this.ListView.setAdapter(adapter);
this.ListView.setItemsCanFocus(true);
this.ListView.setOnItemClickListener(this);
this.Activity = (PilotController) getActivity();
this.ButtonStartNewThread = (Button) view.findViewById(R.id.buttonStartThread);
this.ButtonStartNewThread.setOnClickListener(this);
return view;
}
#Override
public void onPause()
{
super.onPause();
this.Paused = true;
}
but when i return to my old list, it's empty. Could you give me some advice?
SOLUTION
I found a solution. ListView is probably removing from 'draw stack' so when calling OnDeleteView your old list is unusable next time although reference to this object is still set. The solution is to recreate ListView and set old adapter. This adapter due to this tutorial http://developer.android.com/guide/components/fragments.html will survive but view is recreated (so old listview doesn't exist anymore (it exist but it's not drawable). I had to change this lines:
if(this.Paused == false){
this.ListView = (ListView) view.findViewById(R.id.listViewActiveThreads);
ArrayList<Guid> strs = new ArrayList<Guid>();
adapter = new ThreadInfoAdapter(view.getContext(), strs, this);
}
to:
this.ListView = (ListView) view.findViewById(R.id.listViewActiveThreads);
if(this.Paused == false){
ArrayList<Guid> strs = new ArrayList<Guid>();
adapter = new ThreadInfoAdapter(view.getContext(), strs, this);
}
In "onActivityCreated" you can just check if your dataList (in your case "strs) is empty. If it is not then just use it, otherwise create a new one. In code it would look like this:
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (strs == null)
strs = new ArrayList<Guid>();
mListView = (ListView)getActivity().findViewById(R.id.listViewActiveThreads);
mPersonAdapter = new ArrayAdapterPerson(getActivity(),mPersonList,this);
mListView.setAdapter(mPersonAdapter);
}
I found my solution here: ListFragment is empty after going back
use transaction.hide(this):
ft.addToBackStack(null);
ft.hide(this);
ft.add(R.id.frag_frame, lyrics);
ft.commit();

set list view adapter in a fragment in android

I want a custom row, so I am using a List View in an xml and inflating into a fragment. I am very confused of how to set the adapter for the list View.
I created a new adapter which extends Base Adapter. In the getView method, I really don't know what context to pass while inflating the row.xml layout.
How do I set the adapter for the list view and where?
public class ResultsFragment extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.results_layout, container, false);
listView = (ListView)v.findViewById(R.id.results);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
loadPage(dataBean.getWhat(), dataBean.getWhere(), dataBean.getPageStart());
//resultsAdapter.setRssData(rssData);
//setListAdapter(resultsAdapter);
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Context context = getActivity().getApplicationContext();
resultsAdapter = new ResultsAdapter(context);
}
/**
* Set List Adapter
*/
private void setAdapter(){
if(listView.getAdapter() == null){
listView.setAdapter(resultsAdapter);
}
else{
resultsAdapter.notifyDataSetChanged();
}
}
}
You must extend Listfragment (instead of Fragment), and using its ListFragment.setListAdapter to set your adapter. In the adapter getView() inflate your row.. that s all
If you do not want to change your extended class, you should use listview.setAdapter(...) method. As you see in my example :
ListView productList= (ListView) getActivity().findViewById(R.id.product_list);
SampleAdapter adapter = new SampleAdapter(getActivity());
adapter.add(new SampleItem(
"Sunny LCD TV 2\" SN022L66-T1 Full HD",
R.drawable.product_sample_pic);
productList.setAdapter(adapter);

Categories

Resources