1

I want to make my listview which only scroll horizontally like flipkart home page.

Here, is my fragment_home.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView  xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:textColor="#000"
            android:textSize="20dp"
            android:layout_marginBottom="1dp"
            android:text="SAREES"/>
        <View
            android:layout_width="fill_parent"
            android:layout_height="1dp"
            android:background="#000">
        </View>
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="250dp"
            android:layout_marginTop="5dp">

            <ListView
                android:id="@+id/sarees_listview"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

            </ListView>
            <!--<android.support.v4.view.ViewPager-->
            <!--android:id="@+id/sarees_viewPager"-->
            <!--android:layout_width="fill_parent"-->
            <!--android:layout_height="fill_parent"-->
            <!--android:layout_gravity="center"-->
            <!--android:layout_marginLeft="10dp"-->
            <!--android:layout_marginRight="10dp"-->
            <!--android:background="@android:color/transparent" />-->

        </LinearLayout>
    </LinearLayout>
</ScrollView>

Here, is my Adapter class which inflate listview items

package adapter;

import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;

import com.domore.onlineangelnx.R;

import java.util.List;


public class SareesPagerAdapter extends BaseAdapter{

    private Context context;
    private List<String> list;

    private LayoutInflater inflater;
    public SareesPagerAdapter(Context context,List<String> list){
        this.context=context;
        this.list=list;

    }
    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int position) {
        return position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        if(convertView==null){
            inflater=(LayoutInflater)this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView=inflater.inflate(R.layout.sarees_view_pager,null);
//            ImageView img=(ImageView)convertView.findViewById(R.id.img_nature);
        }
        return convertView;
    }
}

Here, is my sarees_view_pager.xml which has imageView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="match_parent">

    <HorizontalScrollView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="match_parent">

            <ImageView
                android:id="@+id/img_nature"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/test"/>
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/test"/>
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/test"/>
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/test"/>
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/test"/>
        </LinearLayout>
    </HorizontalScrollView>
</LinearLayout>

Here, is homefragment.java which inflate home_fragment.xml

package MainFragments;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;

import com.domore.onlineangelnx.R;

import java.util.ArrayList;
import java.util.List;

import adapter.SareesPagerAdapter;

public class HomeFragment extends Fragment {

    View rootView;
    SareesPagerAdapter adapter;
    List<String> items=null;
    ListView listview;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        rootView=inflater.inflate(R.layout.home_fragment, container, false);

        listview=(ListView)rootView.findViewById(R.id.sarees_listview);
        items=new ArrayList<>();
        items.add("well done");
        items.add("well done");
        items.add("well done");
        items.add("well done");


        adapter=new SareesPagerAdapter(getContext(),items);
        listview.setAdapter(adapter);
        return rootView;
    }
}

HomeFragment.java which set the listview items and call the adapter class. Problem is my listview display it's items in vertically and horizontally both way.

Please, help me to solve out this problem.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Milan Gajera
  • 962
  • 2
  • 14
  • 41

2 Answers2

0

We need to create our own horizontalListView class because android provide a listview with vertical scroll by default.

Here, is the code to create horizontalListView.java.

package HorizontalListView;

import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.Scroller;

import java.util.LinkedList;
import java.util.Queue;

public class HorizontalListView extends AdapterView<ListAdapter> {

    public boolean mAlwaysOverrideTouch = true;
    protected ListAdapter mAdapter;
    private int mLeftViewIndex = -1;
    private int mRightViewIndex = 0;
    protected int mCurrentX;
    protected int mNextX;
    private int mMaxX = Integer.MAX_VALUE;
    private int mDisplayOffset = 0;
    protected Scroller mScroller;
    private GestureDetector mGesture;
    private Queue<View> mRemovedViewQueue = new LinkedList<View>();
    private OnItemSelectedListener mOnItemSelected;
    private OnItemClickListener mOnItemClicked;


    public HorizontalListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    private void initView() {
        mLeftViewIndex = -1;
        mRightViewIndex = 0;
        mDisplayOffset = 0;
        mCurrentX = 0;
        mNextX = 0;
        mMaxX = Integer.MAX_VALUE;
        mScroller = new Scroller(getContext());
        mGesture = new GestureDetector(getContext(), mOnGesture);
    }

    @Override
    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
        mOnItemSelected = listener;
        Log.v("log_tag", "Message is set On Clicked");
    }

    @Override
    public void setOnItemClickListener(OnItemClickListener listener){
        mOnItemClicked = listener;
        Log.v("log_tag", "Set on Item Clicked");
    }

    private DataSetObserver mDataObserver = new DataSetObserver() {

        @Override
        public void onChanged() {
            // TODO Auto-generated method stub
            super.onChanged();
        }

        @Override
        public void onInvalidated() {
            // TODO Auto-generated method stub
            super.onInvalidated();
        }

    };

    @Override
    public ListAdapter getAdapter() {
        return mAdapter;
    }

    @Override
    public View getSelectedView() {
        //TODO: implement
        return null;
    }

    @Override
    public void setAdapter(ListAdapter adapter) {
        if(mAdapter != null) {
            mAdapter.unregisterDataSetObserver(mDataObserver);
        }
        mAdapter = adapter;
        mAdapter.registerDataSetObserver(mDataObserver);
        initView();
        removeAllViewsInLayout();
        requestLayout();
    }

    @Override
    public void setSelection(int position) {
        //TODO: implement
    }

    private void addAndMeasureChild(final View child, int viewPos) {
        LayoutParams params = child.getLayoutParams();
        if(params == null) {
            params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
        }

        addViewInLayout(child, viewPos, params, true);
        child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
                MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
    }

    @Override
    protected synchronized void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        if(mAdapter == null){
            return;
        }

        if(mScroller.computeScrollOffset()){
            int scrollx = mScroller.getCurrX();
            mNextX = scrollx;
        }

        if(mNextX < 0){
            mNextX = 0;
            mScroller.forceFinished(true);
        }
        if(mNextX > mMaxX) {
            mNextX = mMaxX;
            mScroller.forceFinished(true);
        }

        int dx = mCurrentX - mNextX;

        removeNonVisibleItems(dx);
        fillList(dx);
        positionItems(dx);

        mCurrentX = mNextX;

        if(!mScroller.isFinished()){
            post(new Runnable(){
                @Override
                public void run() {
                    requestLayout();
                }
            });

        }
    }

    private void fillList(final int dx) {
        int edge = 0;
        View child = getChildAt(getChildCount()-1);
        if(child != null) {
            edge = child.getRight();
        }
        fillListRight(edge, dx);

        edge = 0;
        child = getChildAt(0);
        if(child != null) {
            edge = child.getLeft();
        }
        fillListLeft(edge, dx);


    }

    private void fillListRight(int rightEdge, final int dx) {
        while(rightEdge + dx < getWidth() && mRightViewIndex < mAdapter.getCount()) {

            View child = mAdapter.getView(mRightViewIndex, mRemovedViewQueue.poll(), this);
            addAndMeasureChild(child, -1);
            rightEdge += child.getMeasuredWidth();

            if(mRightViewIndex == mAdapter.getCount()-1){
                mMaxX = mCurrentX + rightEdge - getWidth();
            }
            mRightViewIndex++;
        }

    }

    private void fillListLeft(int leftEdge, final int dx) {
        while(leftEdge + dx > 0 && mLeftViewIndex >= 0) {
            View child = mAdapter.getView(mLeftViewIndex, mRemovedViewQueue.poll(), this);
            addAndMeasureChild(child, 0);
            leftEdge -= child.getMeasuredWidth();
            mLeftViewIndex--;
            mDisplayOffset -= child.getMeasuredWidth();
        }
    }

    private void removeNonVisibleItems(final int dx) {
        View child = getChildAt(0);
        while(child != null && child.getRight() + dx <= 0) {
            mDisplayOffset += child.getMeasuredWidth();
            mRemovedViewQueue.offer(child);
            removeViewInLayout(child);
            mLeftViewIndex++;
            child = getChildAt(0);

        }

        child = getChildAt(getChildCount()-1);
        while(child != null && child.getLeft() + dx >= getWidth()) {
            mRemovedViewQueue.offer(child);
            removeViewInLayout(child);
            mRightViewIndex--;
            child = getChildAt(getChildCount()-1);
        }
    }

    private void positionItems(final int dx) {
        if(getChildCount() > 0){
            mDisplayOffset += dx;
            int left = mDisplayOffset;
            for(int i=0;i<getChildCount();i++){
                View child = getChildAt(i);
                int childWidth = child.getMeasuredWidth();
                child.layout(left, 0, left + childWidth, child.getMeasuredHeight());
                left += childWidth;
            }
        }
    }

    public synchronized void scrollTo(int x) {
        mScroller.startScroll(mNextX, 0, x - mNextX, 0);
        requestLayout();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean handled = mGesture.onTouchEvent(ev);
        return handled;
    }

    protected boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                              float velocityY) {
        synchronized(HorizontalListView.this){
            mScroller.fling(mNextX, 0, (int)-velocityX, 0, 0, mMaxX, 0, 0);
        }
        requestLayout();

        return true;
    }

    protected boolean onDown(MotionEvent e) {
        mScroller.forceFinished(true);
        return true;
    }

    private OnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener() {

        @Override
        public boolean onDown(MotionEvent e) {
            return HorizontalListView.this.onDown(e);
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                               float velocityY) {
            return HorizontalListView.this.onFling(e1, e2, velocityX, velocityY);
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                                float distanceX, float distanceY) {

            synchronized(HorizontalListView.this){
                mNextX += (int)distanceX;
            }
            requestLayout();

            return true;
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            Rect viewRect = new Rect();
            for(int i=0;i<getChildCount();i++){
                View child = getChildAt(i);
                int left = child.getLeft();
                int right = child.getRight();
                int top = child.getTop();
                int bottom = child.getBottom();
                viewRect.set(left, top, right, bottom);
                if(viewRect.contains((int)e.getX(), (int)e.getY())){
                    if(mOnItemClicked != null){
                        mOnItemClicked.onItemClick(HorizontalListView.this, child, mLeftViewIndex + 1 + i, 0);
                    }
                    if(mOnItemSelected != null){
                        mOnItemSelected.onItemSelected(HorizontalListView.this, child, mLeftViewIndex + 1 + i, 0);
                    }
                    break;
                }

            }
            return true;
        }
    };
}

Above class will help you to create horizontal custom or built-in listview.

Use HorizontalListView control insted of listiview in your xml.

<HorizontalListView.HorizontalListView
                android:id="@+id/sarees_listview"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:background="#ddd"
                />

To use this technique you will able to scroll your items in horizontal mode.Thanx a lot.

Milan Gajera
  • 962
  • 2
  • 14
  • 41
0

You can use Recycleview with orientation:horizontal. You have to add dependency is your build.gradle file:

compile 'com.android.support:recyclerview-v7:24.0.0-alpha1'

Add the following code in xml file where you want to display horizontal scrollable list .

 <android.support.v7.widget.RecyclerView
            android:id="@+id/recycleview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:clipToPadding="false"
            android:orientation="horizontal"
            android:padding="10dp"
            app:layoutManager="LinearLayoutManager"
            tools:listitem="@layout/your_single_item_layout">

        </android.support.v7.widget.RecyclerView>

in your activity or fragment :

recycleAdapter = new CustomRecycleAdapter(festivalObj.getArtist_list());
            recycleview.setAdapter(recycleAdapter);

You have to create a custom adapter where you can define your cell layout. You can read more here: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html http://blog.lovelyhq.com/creating-lists-with-recyclerview-in-android/

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Harshal Bhatt
  • 731
  • 10
  • 25