Fast scroll in ListView

Fast scroll in ListView

Sometimes when the list is very big, We need to make a fast scroll view. FastScroll is something like that:

Now we leart how to make a fast scroll in listView.
We need these things:

-Style in values-v14.
-Style.
-Colors.
-Layout.
-An adapter for list.
-Activity.

in directory values-v14/styles.xml we have to add three things:
fastScrollThumbDrawable
fastScrollTextColor
fastScrollPreviewBackgroundRight

<?xml version="1.0" encoding="utf-8"?>
<resources>
 
    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
        <!-- API 14 theme customizations can go here. -->
        <item name="android:fastScrollThumbDrawable">@drawable/fastscroll_thumb_holo</item>
        <item name="android:fastScrollTextColor">@android:color/white</item>
        <item name="android:fastScrollPreviewBackgroundRight">@color/apptheme_color</item>
    </style>
 
</resources>

In directory values/styles.xml

<resources>
 
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:fastScrollThumbDrawable">@drawable/fastscroll_thumb_holo</item>
        <item name="android:fastScrollTextColor">@android:color/white</item>
        <item name="android:fastScrollPreviewBackgroundRight">@color/apptheme_color</item>
    </style>
 
</resources>

In Colors we have to add one color:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="apptheme_color">#DA4A38</color>
</resources>

You can doing without style, so you can skip last steps, and start since here:

The color of the indicator is your colorAccent

You can find the complete code in GitHub

res/layout/list_item

<?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="40dp" />

In activity_layout our listView.

<?xml version="1.0" encoding="utf-8"?>
<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="com.example.javier.fastscrollerwithandroidstyle.MainActivity">
 
    <ListView
        android:id="@+id/activity_main_list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scrollbarStyle="outsideOverlay" />
</RelativeLayout>

Our ListAdapter

public class ListAdapter extends ArrayAdapter<String> implements SectionIndexer {
 
    HashMap<String, Integer> mapIndex;
    String[] sections;
    List<String> fruits;
 
    public ListAdapter(Context context, List<String> fruitList) {
        super(context, R.layout.list_item, fruitList);
 
        this.fruits = fruitList;
        mapIndex = new LinkedHashMap<String, Integer>();
 
        for (int x = 0; x < fruits.size(); x++) {
            String fruit = fruits.get(x);
            String ch = fruit.substring(0, 1);
            ch = ch.toUpperCase(Locale.US);
 
            // HashMap will prevent duplicates
            mapIndex.put(ch, x);
        }
 
        Set<String> sectionLetters = mapIndex.keySet();
 
        // create a list from the set to sort
        ArrayList<String> sectionList = new ArrayList<String>(sectionLetters);
 
        Log.d("sectionList", sectionList.toString());
        Collections.sort(sectionList);
 
        sections = new String[sectionList.size()];
 
        sectionList.toArray(sections);
    }
 
    public int getPositionForSection(int section) {
        Log.d("section", "" + section);
        return mapIndex.get(sections[section]);
    }
 
    public int getSectionForPosition(int position) {
        Log.d("position", "" + position);
        return 0;
    }
 
    public Object[] getSections() {
        return sections;
    }
}

In our activity

public class MainActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        ListView listView = (ListView) findViewById(R.id.activity_main_list);
        listView.setFastScrollEnabled(true);
        String[] fruits = getResources().getStringArray(R.array.fruits_array);
 
        List<String> fruitList = Arrays.asList(fruits);
        ListAdapter listAdapter = new ListAdapter(this, fruitList);
        listView.setAdapter(listAdapter);
 
    }
}

And in our strings, something like that:

<resources>
    <string name="app_name">FastScrollerWithAndroidStyle</string>
    <string-array name="fruits_array">
        <item>Apples</item>
        <item>Apricots</item>
        <item>Avocado</item>
        <item>Annona</item>
        <item>Banana</item>
        <item>Bilberry</item>
        <item>Blackberry</item>
        <item>Custard Apple</item>
        <item>Clementine</item>
        <item>Cantalope</item>
        <item>Coconut</item>
        <item>Currant</item>
        <item>Cherry</item>
        <item>Cherimoya</item>
        <item>Date</item>
        <item>Damson</item>
        <item>Durian</item>
        <item>Elderberry</item>
        <item>Fig</item>
        <item>Feijoa</item>
        <item>Grapefruit</item>
        <item>Grape</item>
        <item>Gooseberry</item>
        <item>Guava</item>
        <item>Honeydew melon</item>
        <item>Huckleberry</item>
        <item>Jackfruit</item>
        <item>Juniper Berry</item>
        <item>Jambul</item>
        <item>Jujube</item>
        <item>Kiwi</item>
        <item>Kumquat</item>
        <item>Lemons</item>
        <item>Limes</item>
        <item>Lychee</item>
        <item>Mango</item>
        <item>Mandarin</item>
        <item>Mangostine</item>
        <item>Nectaraine</item>
        <item>Orange</item>
        <item>Olive</item>
        <item>Prunes</item>
        <item>Pears</item>
        <item>Plum</item>
        <item>Pineapple</item>
        <item>Peach</item>
        <item>Papaya</item>
        <item>Passionfruit</item>
        <item>Pomegranate</item>
        <item>Pomelo</item>
        <item>Raspberries</item>
        <item>Rock melon</item>
        <item>Rambutan</item>
        <item>Strawberries</item>
        <item>Sweety</item>
        <item>Salmonberry</item>
        <item>Satsuma</item>
        <item>Tangerines</item>
        <item>Tomato</item>
        <item>Ugli</item>
        <item>Watermelon</item>
        <item>Woodapple</item>
    </string-array>
</resources>

You can find the complete code in GitHub

Horizontal ListView on Android

Horizontal ListView on Android

Actually android doesn’t have a listView horizontal. So We will see how to make.

horizontal

We need these things:
*Activity and layout.
*Adapter and list_item.
*Data object.
*DividerItemDecoration (it divides our item).

As per Android Documentaion recyclerview is the new way to organize the items in listview and to be displayed horizontally.

Advantages:

*Since by using Recyclerview Adapter, ViewHolder pattern is automatically implemented
*Animation is easy to perform
*Many more features

The code is in GitHub

In your dependencies you add this line

compile "com.android.support:recyclerview-v7:24.0.0"

dimens.xml

<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_main_horizontal_margin">16dp</dimen>
    <dimen name="activity_main_vertical_margin">16dp</dimen>
      
    <dimen name="activity_main_height">150dp</dimen>
</resources>

list_item.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">
    <TextView
        android:id="@+id/item_list_view_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="@dimen/activity_main_vertical_margin"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />
  
    <TextView
        android:id="@+id/item_list_view_text_view_two"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="@dimen/activity_main_vertical_margin"
        android:text="Small Text"
        android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:context="com.example.javier.recyclerviewhorizontallistviewtwo.MainActivity">
  
    <android.support.v7.widget.RecyclerView
        android:id="@+id/activity_main_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="@dimen/activity_main_height"
        android:background="@android:color/darker_gray" />
  
</RelativeLayout>

Our data
Data.java

public class HorizontalData {
    private String mTitle;
    private String mSubTitle;

    HorizontalData(String title, String subTitle){
        mTitle = title;
        mSubTitle = subTitle;
    }

    public String getmTitle() {
        return mTitle;
    }

    public void setmTitle(String mTitle) {
        this.mTitle = mTitle;
    }

    public String getmSubTitle() {
        return mSubTitle;
    }

    public void setmSubTitle(String mSubTitle) {
        this.mSubTitle = mSubTitle;
    }
}

DividerItemDecoration.java

package com.example.javier.swipe;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * Created by javierg on 16/02/16.
 */
public class DividerItemDecoration extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[]{
            android.R.attr.listDivider
    };

    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
    private Drawable mDivider;
    private int mOrientation;

    public DividerItemDecoration(Context context, int orientation) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
        setOrientation(orientation);
    }

    public void setOrientation(int orientation) {
        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
            throw new IllegalArgumentException("invalid orientation");
        }
        mOrientation = orientation;
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            drawVertical(c, parent);
        } else {
            drawHorizontal(c, parent);
        }
    }

    public void drawVertical(Canvas c, RecyclerView parent) {
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    public void drawHorizontal(Canvas c, RecyclerView parent) {
        final int top = parent.getPaddingTop();
        final int bottom = parent.getHeight() - parent.getPaddingBottom();
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        }
    }
}

CustomRecyclerViewAdapter.java

public class HorizontalRecyclerViewAdapter extends RecyclerView
        .Adapter<HorizontalRecyclerViewAdapter
        .DataObjectHolder> {
    private static String LOG_TAG = "MyRecyclerViewAdapter";
    private ArrayList<HorizontalData> mDataset;
    private static MyClickListener myClickListener;

    public static class DataObjectHolder extends RecyclerView.ViewHolder
            implements View
            .OnClickListener {
        TextView mLabel;
        TextView mDateTime;

        public DataObjectHolder(View itemView) {
            super(itemView);
            mLabel = (TextView) itemView.findViewById(R.id.horizontal_list_item_text_view);
            mDateTime = (TextView) itemView.findViewById(R.id.horizontal_list_item_text_view_two);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            myClickListener.onItemClick(getAdapterPosition(), v);
        }
    }

    public void setOnItemClickListener(MyClickListener myClickListener) {
        this.myClickListener = myClickListener;
    }

    public HorizontalRecyclerViewAdapter(ArrayList<HorizontalData> myDataset) {
        mDataset = myDataset;
    }

    @Override
    public DataObjectHolder onCreateViewHolder(ViewGroup parent,
                                               int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.horizontal_list_item, parent, false);

        DataObjectHolder dataObjectHolder = new DataObjectHolder(view);
        return dataObjectHolder;
    }

    @Override
    public void onBindViewHolder(DataObjectHolder holder, int position) {
        holder.mLabel.setText(mDataset.get(position).getmTitle());
        holder.mDateTime.setText(mDataset.get(position).getmSubTitle());
    }

    public void addItem(HorizontalData dataObj, int index) {
        mDataset.add(dataObj);
        notifyItemInserted(index);
    }

    public void deleteItem(int index) {
        mDataset.remove(index);
        notifyItemRemoved(index);
    }

    @Override
    public int getItemCount() {
        return mDataset.size();
    }

    public interface MyClickListener {
        public void onItemClick(int position, View v);
    }
}

Our Activity or Fragment

public class HorizontalFragment extends Fragment implements HorizontalRecyclerViewAdapter.MyClickListener{
    private RecyclerView mRecyclerView;
    private HorizontalRecyclerViewAdapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
    private static String LOG_TAG = "RecyclerViewActivity";

    public HorizontalFragment() {
        // Required empty public constructor
    }

    public static HorizontalFragment newInstance() {
        HorizontalFragment fragment = new HorizontalFragment();
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.horizontal_fragment, container, false);
        mRecyclerView = (RecyclerView) view.findViewById(R.id.fragment_horizontal_recycler_view);
        mRecyclerView.setHasFixedSize(true);


        mLayoutManager = new LinearLayoutManager(getActivity(),LinearLayoutManager.HORIZONTAL, false);//new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);


        mAdapter = new HorizontalRecyclerViewAdapter(getDataSet());
        mRecyclerView.setAdapter(mAdapter);
        RecyclerView.ItemDecoration itemDecoration =
                new DividerItemDecoration(getActivity(), LinearLayoutManager.HORIZONTAL);
        mRecyclerView.addItemDecoration(itemDecoration);
        mAdapter.setOnItemClickListener(this);


        // Code to Add an item with default animation
        //((MyRecyclerViewAdapter) mAdapter).addItem(obj, index);

        // Code to remove an item with default animation
        //((MyRecyclerViewAdapter) mAdapter).deleteItem(index);


        return view;
    }

    private ArrayList<HorizontalData> getDataSet() {
        ArrayList results = new ArrayList<>();
        for (int index = 0; index < 20; index++) {
            HorizontalData obj = new HorizontalData("Some Primary Text " + index,
                    "Secondary " + index);
            results.add(index, obj);
        }
        return results;
    }


    @Override
    public void onItemClick(int position, View v) {
        Log.i(LOG_TAG, " Clicked on Item " + position);
    }
}

Now We have our horizontal ListView.

The code is in GitHub

Expandable Listview inside scrollview

Expandable listview inside scrollview

When we have a ListView expandable inside ScrollView, we must make this in our layout, always expandable listview must be the last view in our layout:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_expandable_scroll_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <LinearLayout
        android:id="@+id/LinearLayout1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin">

<!-- your code --->

 <ExpandableListView
            android:id="@+id/activity_expandable_list_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/white"/>

    </LinearLayout>
</ScrollView>

In your onCreate

mListView = (ExpandableListView) findViewById(R.id.activity_expandable_list_view);
        MyExpandableListAdapter adapter = new MyExpandableListAdapter(this,
                mGroups);
        mListView.setAdapter(adapter);
        mListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {

            @Override
            public boolean onGroupClick(ExpandableListView parent, View v,
                                        int groupPosition, long id) {
                setListViewHeight(parent, groupPosition);
                return false;
            }
        });

You need this function:

    private void setListViewHeight(ExpandableListView listView,
                                   int group) {
        ExpandableListAdapter listAdapter = (ExpandableListAdapter) listView.getExpandableListAdapter();
        int totalHeight = 0;
        int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(),
                View.MeasureSpec.EXACTLY);
        for (int i = 0; i < listAdapter.getGroupCount(); i++) {
            View groupItem = listAdapter.getGroupView(i, false, null, listView);
            groupItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);

            totalHeight += groupItem.getMeasuredHeight();

            if (((listView.isGroupExpanded(i)) && (i != group))
                    || ((!listView.isGroupExpanded(i)) && (i == group))) {
                for (int j = 0; j < listAdapter.getChildrenCount(i); j++) {
                    View listItem = listAdapter.getChildView(i, j, false, null,
                            listView);
                    listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);

                    totalHeight += listItem.getMeasuredHeight();

                }
            }
        }

        ViewGroup.LayoutParams params = listView.getLayoutParams();
        int height = totalHeight
                + (listView.getDividerHeight() * (listAdapter.getGroupCount() - 1));
        if (height < 10)
            height = 200;
        params.height = height;
        listView.setLayoutParams(params);
        listView.requestLayout();

    }

Download code

ListView inside ScrollView II

See only one item

You do not have to do anything special in layout.xml file nor handle anything on the parent ScrollView. You only have to handle the child ListView. You can also use this code to use any type of child view inside a ScrollView & perform Touch operations.

ScrollView inside ListView

Just add these lines of code in your java class :

listView.setOnTouchListener(new ListView.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // Disallow the touch request for parent scroll on touch of child view
                v.getParent().requestDisallowInterceptTouchEvent(true);
                return false;
            }
        });

Download code

ListView inside ScrollView

You Create Custom ListView Which is non Scrollable

http://thedeveloperworldisyours.com/

Download code

public class NonScrollListView extends ListView {

    public NonScrollListView(Context context) {
        super(context);
    }
    public NonScrollListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public NonScrollListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int heightMeasureSpec_custom = View.MeasureSpec.makeMeasureSpec(
                Integer.MAX_VALUE >> 2, View.MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
        ViewGroup.LayoutParams params = getLayoutParams();
        params.height = getMeasuredHeight();
    }
}

In Your Layout File

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fadingEdgeLength="0dp"
    android:fillViewport="true"
    android:overScrollMode="never"
    android:scrollbars="none" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <!-- com.Example Changed with your Package name -->

        <com.thedeveloperworldisyours.view.NonScrollListView
            android:id="@+id/lv_nonscroll_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
        </com.thedeveloperworldisyours.view.NonScrollListView>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/lv_nonscroll_list" >

            <!-- Your another layout in scroll view -->

        </RelativeLayout>
    </RelativeLayout>

</ScrollView>

In Java File

Create a object of your customListview instead of ListView like :

NonScrollListView non_scroll_list = (NonScrollListView) findViewById(R.id.lv_nonscroll_list);

Download code