Introduction:

ListView is a list display, now I generally use is RecyclerView, but the use of ListView is still very wide.

The main content

  • ListView common techniques
  • ListView

The specific content

ListView is a common component in Android development. It presents specific content in the form of a list and ADAPTS to the length of the data.

ListView common techniques

ListView common techniques:

  • Use the ViewHolder pattern for efficiency
  • Set dividing lines between projects
  • Hide the ListView scroll bar
  • Unclick the Item from the ListView
  • Set the number on which the ListView should be displayed
  • Dynamically modify the ListView
  • Iterate over all items in the ListView
  • Dealing with empty ListView
  • ListView sliding listens
Use the ViewHolder pattern for efficiency

ViewHolder takes full advantage of ListView’s view caching mechanism, avoiding the need to instantiate the control with findViewById() every time getView() is called. Using ViewHolder has been tested to increase efficiency by more than 50%.

public class ViewHolderAdapter extends BaseAdapter{

    private List<String> mData;
    private LayoutInflater mInflater;

    public ViewHolderAdapter(Context context, List<String> mData) {
        this.mData = mData;
        mInflater = LayoutInflater.from(context);
    }

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

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        // Check whether there is a cache
        if (convertView == null) {
            holder = new ViewHolder();
            // Instantiate the layout with LayoutInflater
            convertView = mInflater.inflate(R.layout.viewholder_item, null);
            holder.img = (ImageView) convertView.findViewById(R.id.imageView);
            holder.title = (TextView) convertView.findViewById(R.id.textView);
            convertView.setTag(holder);
        } else {
            // Find the cache layout using the tag
            holder = (ViewHolder) convertView.getTag();
        }
        // Sets the view to display for the control in the layout
        holder.img.setBackgroundResource(R.mipmap.ic_launcher);
        holder.title.setText(mData.get(position));
        return convertView;
    }

    public final class ViewHolder {
        public ImageView img;
        publicTextView title; }}Copy the code
Set dividing lines between projects

Set the dividing line with color and thickness.

android:dividerHeight="10dp"
android:divider="@android:color/darker_gray"
Copy the code

Set a cut-off line.

android:divider="@null"
Copy the code
Hide the ListView scroll bar
android:scrollbars="none"
Copy the code
Unclick the Item from the ListView
android:listSelector="@android:color/transparent"
Copy the code
Set the number on which the ListView should be displayed

I slide naturally to the NTH term.

listview.setSelection(n);
Copy the code

Instantaneous slide to what term and natural slide to the NTH term.

listview.smoothScrollBy(distance,duration);
listview.smoothScrollByOffset(offset);
listview.smoothScrollToPosition(index);
Copy the code
Dynamically modify the ListView

When data changes, you can use notifyDataSetChanged() to refresh the ListView, but you must ensure that the List of data passed into the Adapter using this method is the same List and not another object.

mData.add("new");
mAdapter.notifyDataSetChanged();
Copy the code
Iterate over all items in the ListView
for (int i = 0; i < mListview.getChildCount(); i++){ View view = mListview.getChildAt(i); }Copy the code
Dealing with empty ListView

In the development, will encounter the ListView is empty, such as: shopping cart without adding items, need to display the shopping cart without any items of the View, this time is the ListView data is empty, ListView for us to provide a good method. In the FrameLayout where the ListView exists, add an ImageView to display as an empty ListView.


      
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ImageView
        android:id="@+id/empty_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>
Copy the code

Display the layout when implementing ListView empty data in the Activity

ListView listView = (ListView)findViewById(R.id.listview);
listview.setEmptyView(findViewById(R.id.tv_null));
Copy the code
ListView sliding listens

OnTouchListener:

  • Motionevent. ACTION_DOWN: Action when touching.
  • Motionevent. ACTION_MOVE: Action when moving.
  • Motionevent. ACTION_UP: Action when leaving.
mListview.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // Operate when touched
                break;
            case MotionEvent.ACTION_MOVE:
                // Operate while moving
                break;
            case MotionEvent.ACTION_UP:
                // Operate when leaving
                break;
        }
        return false; }});Copy the code

OnScrollListener and onScroll:

  • OnScrollListener.SCROLL_STATE_IDLE: when sliding stops.
  • Onscrolllistener. SCROLL_STATE_TOUCH_SCROLL: scrolling.
  • Onscrolllistener. SCROLL_STATE_FLING: When a finger is thrown.
mListview.setOnScrollListener(new OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
                       switch (scrollState) {
            case OnScrollListener.SCROLL_STATE_IDLE:
                // The scroll stops
                break;
            case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                // Is rolling
                break;
            case OnScrollListener.SCROLL_STATE_FLING:
                // When the finger flips
                break; }}@Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        // keep calling while scrolling}});Copy the code

OnScroll parameters:

  • FirstVisibleItem: ID of the first Item that is currently visible.
  • VisibleItemCount: Total number of items currently visible.
  • TotalItemCount: Total number of items in the entire ListView.

The parameter of onScroll method can be used to determine the scroll to the last line:

if(firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount>0) {// Scroll to the last line
}
Copy the code

Judge up and down:

if(firstVisibleItem > LastVisibleItemPosition){
    / / slide
}else if(firstVisibleItem < LastVisibleItemPosition){
    / / decline in
}
LastVisibleItemPosition = firstVisibleItem;
Copy the code

The ListView also gives us an encapsulated way to get information such as the currently visible position of the Item:

// Get the id of the last item in the viewable area
mListview.getLastVisiblePosition();
// Get the id of the first item in the viewable area
mListview.getFirstVisiblePosition();
Copy the code

ListView

ListView

  • An elastic ListView
  • Automatically shows and hides the layout of the ListView
  • Chat ListView
  • Dynamically change the ListView layout
An elastic ListView

By default, Android slides to the top or bottom with only a shadow, which changes to a semicircular shadow after 5.x. On IOS, lists are elastic, so when you scroll to the top or bottom, you scroll a little bit further, so it’s kind of friendly, so let’s try to emulate that.

When we look at the ListView source code, we will find a control to slide to the edge of the processing method.

@Override
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
    }
Copy the code

So we can see that the parameter maxOverScrollY, which controls the number of slides, defaults to 0, and we rewrite the ListView.

package com.lgl.listviewdemo;

import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.widget.ListView;

/** * Created by LGL on 16/3/20. */
public class ListViewScroll extends ListView {

    private int mMaxOverdistance ;

    public ListViewScroll(Context context, AttributeSet attrs) {
        super(context, attrs);

        // Adjust the sliding scale by resolution
        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        float density = metrics.density;
        mMaxOverdistance = (int)(density*mMaxOverdistance);

    }


    @Override
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, mMaxOverdistance, maxOverScrollY, isTouchEvent); }}Copy the code
Automatically shows and hides the layout of the ListView

If you’ve seen Google’s latest app, or if you’ve used an MD-style app, you’ll know that the ActionBar can be shown or hidden depending on the status of the list as it slides.

public class ShowAndHideListViewActivity extends AppCompatActivity {

    private int mTouchSlop;
    private ObjectAnimator mAnimator;
    private Toolbar mToolBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_show_and_hide_list_view);
        // Add headers
        mToolBar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(mToolBar);
        // Populate the layout
        ListView mListView = (ListView) findViewById(R.id.lv);
        String[] str = new String[]{"1"."2"."3"."4"."5"."6"."Seven"."8"."9"};
        mListView.setAdapter(new ArrayAdapter<String>(this, R.layout.list_item, R.id.tv, str));
        // Add a header layout to prevent the first data from being covered
        View header = new View(this);
        header.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
                (int) getResources().getDimension(android.support.v7.
                        appcompat.R.dimen.abc_action_bar_default_height_material)));
        mListView.addHeaderView(header);
        / / get TouchSlop
        mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
        // Set the listener
        mListView.setOnTouchListener(myTouchListener);
    }

    View.OnTouchListener myTouchListener = new View.OnTouchListener() {

        public boolean mShow;
        public int direction;

        public float mCurrentY;
        public float mFirstY;

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mFirstY = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    mCurrentY = event.getY();
                    if (mCurrentY - mFirstY > mTouchSlop) {
                        direction = 0;//down
                    } else if (mFirstY - mCurrentY > mTouchSlop) {
                        direction = 1;//up
                    }
                    if (direction == 1) {
                        if (mShow) {
                            toolBarAnim(0);//hide
                            mShow = !mShow;
                        }
                    } else if (direction == 0) {
                        if(! mShow) { toolBarAnim(1);//up
                            mShow = !mShow;
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:

                    break;
            }
            return false; }};private void toolBarAnim(int flag) {
        if(mAnimator ! =null && mAnimator.isRunning()) {
            mAnimator.cancel();
        }
        if (flag == 0) {
            //up:hide
            mAnimator = ObjectAnimator.ofFloat(mToolBar, "translationY", -mToolBar.getHeight());
        } else {
            //down:show
            mAnimator = ObjectAnimator.ofFloat(mToolBar, "translationY", -mToolBar.getHeight(),0); } mAnimator.start(); }}Copy the code

To write the layout file, remember to set theme to NoActionBar.


      
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="? attr/actionBarSize"
        android:background="? attr/colorPrimary"/>

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>
Copy the code
Chat ListView

An important step to achieve this effect is the padding of the left and right layouts. The renderings are as follows.

The left layout:


      
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/left_icon"
        android:layout_width="50dp"
        android:layout_height="50dp" />

    <TextView
        android:id="@+id/tv_left"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="30dp" />

</LinearLayout>
Copy the code

Right layout:


      
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/tv_right"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:padding="30dp" />

    <ImageView
        android:id="@+id/right_icon"
        android:layout_width="50dp"
        android:layout_height="50dp" />
</LinearLayout>
Copy the code

Chat entity class:

public class ChatItemListViewBean {

    private int type;
    private String text;
    private Bitmap icon;

    public int getType(a) {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public String getText(a) {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Bitmap getIcon(a) {
        return icon;
    }

    public void setIcon(Bitmap icon) {
        this.icon = icon; }}Copy the code

The key ones are Adapter’s getItemViewType() and getViewTypeCount() methods.

public class ChatListViewAdapter extends BaseAdapter {

    private List<ChatItemListViewBean> mData;
    private LayoutInflater mInflater;

    public ChatListViewAdapter(Context context, List<ChatItemListViewBean> mData) {
        this.mData = mData;
        mInflater = LayoutInflater.from(context);
    }

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

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null) {
            if (getItemViewType(position) == 0) {
                viewHolder = new ViewHolder();
                convertView = mInflater.inflate(R.layout.left_item, null);
                viewHolder.icon = (ImageView) convertView.findViewById(R.id.left_icon);
                viewHolder.text = (TextView) convertView.findViewById(R.id.tv_left);
            } else {
                viewHolder = new ViewHolder();
                convertView = mInflater.inflate(R.layout.right_item, null);
                viewHolder.icon = (ImageView) convertView.findViewById(R.id.right_icon);
                viewHolder.text = (TextView) convertView.findViewById(R.id.tv_right);
            }
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        viewHolder.icon.setImageBitmap(mData.get(position).getIcon());
        viewHolder.text.setText(mData.get(position).getText());

        return convertView;
    }

    @Override
    public int getItemViewType(int position) {
        ChatItemListViewBean bean = mData.get(position);
        return bean.getType();
    }

    @Override
    public int getViewTypeCount(a) {
        return 2;
    }

    public final class ViewHolder {
        public ImageView icon;
        publicTextView text; }}Copy the code

Implement our effect in the main Activity:

public class ChatListViewActivity extends AppCompatActivity {

    private ListView mListView;

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

        mListView = (ListView) findViewById(R.id.lv_chat);
        ChatItemListViewBean bean1 = new ChatItemListViewBean();
        bean1.setType(0);
        bean1.setIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
        bean1.setText("hello how are you?");

        ChatItemListViewBean bean2 = new ChatItemListViewBean();
        bean2.setType(1);
        bean2.setIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
        bean2.setText("find thank you ,and you?");

        List<ChatItemListViewBean> data = new ArrayList<>();
        data.add(bean1);
        data.add(bean2);

        ChatListViewAdapter adapter = new ChatListViewAdapter(this, data); mListView.setAdapter(adapter); }}Copy the code
Dynamically change the ListView layout

Dynamically change the ListView layout as shown below.

public class DongTaiListViewActivity extends AppCompatActivity {

    private DongTaiListViewAdapter adapter;
    private List<String> list;

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

        ListView listView = (ListView) findViewById(R.id.lv_dongtai);
        list = new ArrayList<>();
        list.add("item1");
        list.add("item2");
        list.add("item3");
        list.add("item4");
        adapter = new DongTaiListViewAdapter(this, list);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<? > parent, View view,int position, long id) { adapter.setCurrentItem(position); adapter.notifyDataSetChanged(); }}); }}Copy the code
public class DongTaiListViewAdapter extends BaseAdapter {

    private List<String> list;
    private Context mContext;
    private int mCurrentItem=0;

    public DongTaiListViewAdapter(Context context, List<String> list) {
        this.list = list;
        this.mContext = context;
    }

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

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LinearLayout layout = new LinearLayout(mContext);
        layout.setOrientation(LinearLayout.VERTICAL);
        if (mCurrentItem == position) {
            layout.addView(addFocusView(position));
        } else {
            layout.addView(addNormalView(position));
        }
        return layout;
    }

    private View addFocusView(int i) {
        ImageView iv = new ImageView(mContext);
        iv.setImageResource(R.mipmap.ic_launcher);
        return iv;
    }

    private View addNormalView(int i) {
        LinearLayout layout = new LinearLayout(mContext);
        layout.setOrientation(LinearLayout.HORIZONTAL);
        ImageView iv = new ImageView(mContext);
        iv.setImageResource(R.mipmap.ic_launcher);
        layout.addView(iv, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
        TextView tv = new TextView(mContext);
        tv.setText(list.get(i));
        layout.addView(tv, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
        layout.setGravity(Gravity.CENTER);
        return layout;
    }

    public void setCurrentItem(int position) { mCurrentItem = position; }}Copy the code