Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewPager within ListView row item

I have read a lot of related questions regarding this question. However, none of them has been answered. I am trying to add a ViewPager to each row in the ListView where there are two layouts within the pager. I believe this is doable because of SwipeListView.

Now I have implemented it. However, a blank page is showing with a line in the middle. No rows are appearing.

Enter image description here

Here is my code:

MainActivity + ArrayAdapter

public class MainActivity extends Activity {

    ListView list;
    String[] heros;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        heros = getResources().getStringArray(R.array.heros);

        list = (ListView) findViewById(R.id.listView1);
        list.setAdapter(new CustomAdapter(this, heros));
    }

    public class CustomAdapter extends ArrayAdapter<String>
    {
        String[] heros;
        Context context;
        public CustomAdapter(Context context, String[] heros) {
            super(context, R.layout.pager_item_list, R.id.listView1, heros);
            // TODO Auto-generated constructor stub
            this.heros = heros;
            this.context = context;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View row = inflater.inflate(R.layout.pager_item_list, parent, false);

            Log.d("how many times", "I really don't know how it should be");

            ViewPager pager = (ViewPager) row.findViewById(R.id.pager);
            pager.setId(position);
            pager.setAdapter(new PagerCustomAdapter());

            pager.setCurrentItem(0);

            return row;
        }
    }
}

Here is my pageAdapter

public class PagerCustomAdapter extends PagerAdapter{
    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return 2;
    }

    @Override
    public Object instantiateItem(View container, int position) {
        // TODO Auto-generated method stub

        LayoutInflater inflater = (LayoutInflater) container.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        int id = 0;

        Log.d("I am in pagerAdater", "I am here, dammit!");

        switch(position)
        {
            case 0:
                id = R.layout.fragment_top_item;
                break;
            case 1:
                id = R.layout.fragment_bottom_item;
                break;
        }
        View view = inflater.inflate(id, null);
        ((ViewPager)container).addView(view, 0);
        return view;
    }

    @Override
    public void destroyItem(View arg0, int arg1, Object arg2) {
        ((ViewPager) arg0).removeView((View) arg2);
    }

    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
        // TODO Auto-generated method stub
        return arg0 == ((View) arg1);
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

}

I have tried both pagerAdapter & FragmentPagerAdapter and both had the same result

I added two log messages in getView() and instantiateItem() and both are being read in logcat as expected. There are neither warnings nor errors in LogCat.

What am I missing?

Update

XML of activity_main

<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_centerHorizontal="true"
    android:layout_centerVertical="true" >
</ListView>

</RelativeLayout>

XML of pager_item_list

<?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" >

    <android.support.v4.view.ViewPager
         android:id="@+id/pager"
         android:layout_width="match_parent"
         android:layout_height="match_parent" >
    </android.support.v4.view.ViewPager>
</LinearLayout>
like image 652
Coderji Avatar asked Dec 25 '13 15:12

Coderji


People also ask

Is viewpager in Android widget package?

Our viewpager isn’t in the android.widget package hence we qualify with the full class name of the element. Shall get replaced by our fragments layouts. (b). Model Layout The model for a single row item in our custom listview.

How do I add a viewpager to an existing layout?

Steps for implementing viewpager: Adding the ViewPager widget to the XML layout (usually the main_layout). Creating an Adapter by extending the FragmentPagerAdapter or FragmentStatePagerAdapter class. An adapter populates the pages inside the Viewpager.

What is listview in Android listview?

Android ListView is a ViewGroup which is used to display the list of items in multiple rows and contains an adapter which automatically inserts the items into the list. The main purpose of the adapter is to fetch data from an array or database and insert each item that placed into the list for the desired result.

Where will the data be saved in listview?

The data inside our ListView will be saved in SQLite database. SQLite is a local file-based database written in C programming language and normally comes packaged already with android framework. Of course before retrieving data from the SQLite database we will first need to insert that data in the first place.


Video Answer


2 Answers

I am not sure what you're trying to achieve.. Do you want to change the view when a event happens? like when you click on it? or do you want the same result like the SwipeListView.

If you want to change the view you coult try to use a ViewFlipper anc change the layout when the event occurs. But i'm not sure if this is the result you want

like image 95
Crimson Avatar answered Oct 15 '22 14:10

Crimson


A ViewPager when used inside a ListView row needs to have a unique android:id (as in each row must have a different id). This is because the FragmentManager that is associated with the ViewPager adapter uses the id along with the position to store the fragments. This means if you just use the defaults things will get overwritten.

Below is a sample PagerAdapter that allows you to override the default makeFragmentName method.

import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Parcelable;
import android.support.v13.app.FragmentCompat;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;

public abstract class TaggedFragmentPagerAdapter extends PagerAdapter {

    private final FragmentManager mFragmentManager;

    private FragmentTransaction mCurTransaction = null;

    private Fragment mCurrentPrimaryItem = null;

    public TaggedFragmentPagerAdapter(FragmentManager fm) {
        mFragmentManager = fm;
    }

    /**
     * Return the Fragment associated with a specified position.
     */
    public abstract Fragment getItem(int position);

    public String getItemTag(int position) {
        // Maintain backward compatibility
        return String.valueOf(getItemId(position));
    }

    @Override
    public void startUpdate(ViewGroup container) {
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }

        // Do we already have this fragment?
        String name = makeFragmentName(position, container.getId(), getItemTag(position));
        Fragment fragment = mFragmentManager.findFragmentByTag(name);
        if (fragment != null) {
            // FIXME : Start fix.
            if (!fragment.isDetached()) {
                mCurTransaction.detach(fragment);
            }
            // FIXME : End fix.
            mCurTransaction.attach(fragment);
        } else {
            fragment = getItem(position);
            mCurTransaction.add(container.getId(), fragment, name);
        }
        if (fragment != mCurrentPrimaryItem) {
            FragmentCompat.setMenuVisibility(fragment, false);
            FragmentCompat.setUserVisibleHint(fragment, false);
        }

        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        mCurTransaction.detach((Fragment) object);
    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment) object;
        if (fragment != mCurrentPrimaryItem) {
            if (mCurrentPrimaryItem != null) {
                FragmentCompat.setMenuVisibility(mCurrentPrimaryItem, false);
                FragmentCompat.setUserVisibleHint(mCurrentPrimaryItem, false);
            }
            if (fragment != null) {
                FragmentCompat.setMenuVisibility(fragment, true);
                FragmentCompat.setUserVisibleHint(fragment, true);
            }
            mCurrentPrimaryItem = fragment;
        }
    }

    @Override
    public void finishUpdate(ViewGroup container) {
        if (mCurTransaction != null) {
            mCurTransaction.commitAllowingStateLoss();
            mCurTransaction = null;
            mFragmentManager.executePendingTransactions();
        }
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return ((Fragment) object).getView() == view;
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {
    }

    /**
     * Return a unique identifier for the item at the given position.
     *
     * <p> The default implementation returns the given position. Subclasses should override this method if the positions of items
     * can change. </p>
     *
     * @param position Position within this adapter
     * @return Unique identifier for the item at position
     */
    public long getItemId(int position) {
        return position;
    }

    protected String makeFragmentName(int position, int viewId, String tagName) {
        return "android:switcher:" + viewId + ":" + tagName;
    }
}
like image 20
Andrew Kelly Avatar answered Oct 15 '22 12:10

Andrew Kelly