Slideable lists are a common UI layout effect on Android. So mastery of list controls is a sure thing; RecyclerView is one of the most important and complex list controls and will be explained in detail in another article.

I usually project development necessary framework

  1. The strongest network request Net on Android
  2. The strongest list on Android (including StateLayout) BRV
  3. Android’s strongest default page StateLayout
  4. JSON and long text log printing tool LogCat
  5. Supports asynchronous and global customization of the toast tool Tooltip
  6. Develop the debugging window tool DebugKit
  7. One line of code creates the transparent StatusBar StatusBar

The main control

  • GridView
  • GridLayout
  • ListView
  • Gallery (deprecated, replaced by HorizontalScrollView and ViewPager)
  • ExpandableListView (Extensible list view)
  • Spinner (drop-down view)

ListView

The main function is to reuse lists. Can handle a large number of list control combinations. Before Android21 was one of the most commonly used controls. After introducing RecyclerView control. It’s much more powerful than ListView and much more customizable.

But sometimes it’s more convenient to use ListView than RecyclerView. And there’s no official word that it should be scrapped.

The layout properties

XML attributes that can be used in layout files

attribute describe
android:entries References an array resource to form a list
android:divider Divider (Android: Divider =”@null” to remove dividers)
android:dividerHeight Splitter height (1DP height even if set to 0)
android:footerDividersEnabled Whether to open the foot parting line
android:headerDividersEnabled Whether the head divider will be opened

Preview the item

 tools:listitem="@layout/demo_item"
Copy the code

function

Head layout and foot layout

Add the layout

void addHeaderView (View v, 
                Object data, 
                boolean isSelectable)

void addHeaderView (View v)

void addFooterView (View v, 
                Object data, 
                boolean isSelectable)

void addFooterView (View v)
Copy the code

Delete layout

boolean removeHeaderView (View v)

boolean removeFooterView (View v)
Copy the code

The divider

// Whether the splitter is enabled
boolean areHeaderDividersEnabled (a)
boolean areFooterDividersEnabled (a) 

// Whether to enable the splitter
void setHeaderDividersEnabled (boolean headerDividersEnabled)
void setFooterDividersEnabled (boolean footerDividersEnabled)

// By default, ListView does not cross bounds, so it has no effect by default
void setOverscrollFooter (Drawable footer)
void setOverscrollHeader (Drawable header)

Drawable getOverscrollHeader (a)
Drawable getOverscrollFooter (a)
Copy the code

Get the number of layouts

int getFooterViewsCount (a)

int getHeaderViewsCount (a)
Copy the code

Entry selection

void setSelection (int position)
Copy the code

Smooth scrolling

SmoothScroll represents smooth scrolling, By represents relative distance movement, and To remains unchanged only after being rolled To a specified position

// Relative scroll position
void smoothScrollToPosition (int position)

void smoothScrollByOffset (int offset)
Copy the code

It also inherits the scrollmethod from the AbsListView

// Cancel the fast scroll bar (fast scroll still has a small scroll bar that cannot be dragged)
void setSmoothScrollbarEnabled (boolean enabled)
boolean isSmoothScrollbarEnabled (a)

  
// Smooth scrolling while limiting the maximum scrolling range
void smoothScrollToPosition (int position, 
                int boundPosition) // Range unit: px


// Scroll pixels, and you can control the scrolling duration
void smoothScrollBy (intdistanceint duration)

// The specified scroll position is offset by some distance up
void smoothScrollToPositionFromTop (int position, 
                int offset) // Offset distance
  
// Add control to scroll duration
void smoothScrollToPositionFromTop (int position, 
                int offset, 
                int duration)
Copy the code

rolling

void scrollListBy (int y)
Copy the code

The adapter

Learning adapters distinguish between methods:

  • Methods used to override. This type of method is called to the ListView (the adapter passes the ListView through setAdapter())

  • The method used to invoke. Exposed to the user to control the Item

The ListView adopts the MVC architecture, and the View and Data are controlled by an Adapter. The Adapter used by ListView is the ListAdapter. Set using the setAdapter() method.

The most basic adapter, ListAdapter, is an interface. There are many ways to implement it. An abstract adapter that inherits the ListAdapter is provided for convenience

Adapter inheritance relationship

  • Adapter
    • ListAdapter
      • BaseAdapter
        • SimpleAdapter
        • ArrayAdapter
        • CursorAdapter
          • ResourceCursorADapter
          • SimpleCursorAdapter
      • WrapperListAdapter
        • HeaderViewListAdapter
    • SpinnerAdapter

The above adapter works with ListView and GridView and Spinner.

ListAdapter

ListAdapter is an interface and is generally not used directly because it is not necessary to override all methods. Subclasses are generally used.

// Whether to enable item. If fasle is not enabled, item is unselectable and unclickable
boolean isEnabled(int position); 

// You can see that there is no position argument. So if fasle is returned, all items are disabled
public boolean areAllItemsEnabled(a); 
Copy the code

A method that inherits from a parent class

int getCount (a) // Determine the number of items in the ListView

Object getItem (int position) // Get item data. The value returned here will be used in the ListView

long getItemId (int position)  // Get the item ID. The value returned here will be used in the ListView

// Return the Item type. Whether the type is the same determines whether to reuse Item
int getItemViewType (int position) 

// Returns the contents of the Item view
View getView (intPosition, // View convertView, // ViewGroup parent) / / the parent container

// Return the number of Item types
int getViewTypeCount (a) 
  
// Whether the id is unique
boolean hasStableIds (a) 

boolean isEmpty (a) // Whether it is empty

void registerDataSetObserver (DataSetObserver observer) // Register the data observer

void unregisterDataSetObserver (DataSetObserver observer) // Cancel the data observer
Copy the code

Whether or not the only

HasStableIds () is a method that checks whether the ID is valid. Returns true valid false invalid.

  • Valid case will passgetItemId()Returns the id value to determine if the items are the same
  • If it is invalid, the position of the item is used as the ID by default

BaseAdapter

First I’ll talk about the most common adapter, BaseAdapter.

Features:

  • ListView supports highly customized items

  • You need to rewrite the adapter yourself to use it

Overriding methods

        final String[] title = {"User"."Home page"."Settings"."About"."Feedback"};

// This is an anonymous class
        mListView.setAdapter(new BaseAdapter() {
            /** * Controls the number of items in the ListView *@return* /
            @Override
            public int getCount(a) {
                return title.length;
            }

            /** * Controls the Object data returned by some methods of the ListView, such as the ListView getItemAtPosition() method. The location index yields the data Object, the Object returned by this method * *@param position
             * @return* /
            @Override
            public Object getItem(int position) {
                return null;
            }

            /** * this method is called back every time you click on item. The ListView getItemIdAtPosition() method gets the item ID * *@param position
             * @return* /
            @Override
            public long getItemId(int position) {
                return 0;
            }

            /** * Controls the display of the ListView Item view **@paramPosition Indicates the current view position *@paramConvertView Cached view. Used to reuse item *@paramParent Parent container layout *@return* /
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
              
                View view = View.inflate(MainActivity.this, R.layout.item_list, null);
                
                // Make changes based on incoming data
                TextView text = ButterKnife.findById(view, R.id.text);
                text.setText(title[position]);
                
                returnview; }});Copy the code

Add controls to the main layout

<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.liangjingkanji.listview.MainActivity">

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

</RelativeLayout>
Copy the code

Notice whether parent is enabled when the Inflate Item view is view.

<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/text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
  
</LinearLayout>
Copy the code

I’m not going to write out the layout file. Redundant code affects readability.

This section describes the methods that BaseAdapter adds to the parent ListAdapter class. None of this is necessary

// Check whether the adapter has item
boolean isEmpty (a) 

// **DropDownView** and other methods are overridden SpinnerAdapter. So we'll talk more about that when we talk about Spinner. ListView and GridView are not useful
View getDropDownView (int position, 
                View convertView, 
                ViewGroup parent)
 
boolean hasStableIds (a)

void notifyDataSetChanged (a) // Notify ListView of local updates if data changes

void notifyDataSetInvalidated (a) // If the data changes, notify ListView of the entire update
Copy the code

ArrayAdapter

ArrayAdapter, a subclass of BaseAdapter, is further encapsulated to quickly implement the simplest list of strings (while limiting the data to a single string). Note that this is not an abstract class. You can create objects directly.

Features:

  • All you need is a constructor to create a ListView
  • Customization is weak, and ListView data can only be strings.

When creating an ArrayAdapter, specify the generic ArrayAdapter

. Generics determine the data types accepted by the constructor

A constructor

ArrayAdapter (Context context, / / context
                int resource) // Layout id. Only the layout whose root layout is TextView is supported

ArrayAdapter (Context context, 
                int resource,  // This constructor supports arbitrary layouts
                int textViewResourceId)   // Specify a Textview ID to set the data.

ArrayAdapter (Context context, 
                int resource, 
                T[] objects) // Add data directly to the constructor, which must be an array of strings

ArrayAdapter (Context context, 
                int resource, 
                int textViewResourceId, 
                T[] objects) / / same as above

ArrayAdapter (Context context, 
                int resource, 
                List<T> objects)// Add data set, again must be a string

ArrayAdapter (Context context, 
                int resource, 
                int textViewResourceId, / / same as above
                List<T> objects) // Add data set
Copy the code

The sample


String[] array = {"User"."Home page"."Settings"."About"."Feedback"};

// Android.r.layout. simple_list_item_1 is a TextView layout file provided by the system. You can click open to see the source code.
listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, array));
Copy the code

Doesn’t look like it’s easy to implement the ListView.

Pay attention to

  1. The ListView has already been reused within the ArrayAdapter

  2. The data passed in must be a string. The source code has been judged

  3. The ArrayAdapter does not reuse a ViewHolder.

methods

// Add data
void add (T object)

// Add more data
void addAll (T... items)

// Add collection
void addAll (Collection<? extends T> collection)

// Delete all data
void clear (a)
  
// Delete the specified data
void remove (T object)

// Insert data in the corresponding position
void insert (T object, 
                int index)

// The default is true. So you call the notifyOnChange method every time you modify data. Multiple calls affect efficiency (frequently refreshing the UI). You can set false with this method. You then call methods such as notifyChange yourself to update the UI of the Item.
void setNotifyOnChange (boolean notifyOnChange)

// This is a static method to create a ListView directly. Simple and straightforward
ArrayAdapter<CharSequence> createFromResource (Context context, 
                intTextArrayResId, // Text dataint textViewResId)  // Text control ID

// Get the context passed in
Context getContext (a)

// Get the index from the data
int getPosition (T item)
Copy the code

Here are two more methods to override the filter Item functionality that supports ListView

// Filter, such as association filter for contacts
Filter getFilter (a)

// Use standard comparator sort operations on data
void sort (Comparator<? super T> comparator)
Copy the code

SimpleAdapter

SimpleAdapter is the most complex of the three, but data populates ListView items conveniently. Similarly, non-abstract classes can be used to create objects directly.

Again, the constructor is introduced first

SimpleAdapter (Context context, List<? extends Map<String, ? >> data,Each Item corresponds to a set of maps
                int resource,  // Item layout
                String[] from, // The Map collection is unordered. So you need a key array to control the order
                int[] to) // The data is populated with the View ID corresponding to the array
Copy the code

The sample

Create a ListView as the data

// List collection stores Map collection representative data
List<Map<String, Object>> list = new ArrayList<>();

Map<String, Object> map = new HashMap<>(); 
map.put("icon", R.mipmap.ic_launcher);
map.put("name"."Settings");

Map<String, Object> map2 = new HashMap<>();
map2.put("icon", R.mipmap.ic_launcher);
map2.put("name"."About");

list.add(map);
list.add(map2);

// The value of the String data is the key in the Map collection, corresponding to the control ID in the int array. Populate the corresponding ID control with the value corresponding to the key
listView.setAdapter(new SimpleAdapter(this,list, R.layout.list_item, new String[]{"icon"."name"}, new int[]{R.id.icon, R.id.name}));
Copy the code

SimpleAdapter can only support TextView and Checkable and ImageView property values, if not the three will throw syntax exception messages.

If the ViewBinder interface is passed in, the data population can be handled manually within the callback method

SimpleAdapter.ViewBinder getViewBinder (a)
void setViewBinder (SimpleAdapter.ViewBinder viewBinder)
Copy the code

WrapperListAdapter

As mentioned earlier, this adapter inherits from ListAdapter just like BaseAdapter. But this is the interface. There is only one method inside:

// Return the adapter object. Equivalent getAdapter
ListAdapter getWrappedAdapter (a)
Copy the code

HeaderViewListAdapter

ListAdapter that supports both head and foot layouts

A constructor

// Add two sets of header and foot layouts plus a normal ListAdapter
HeaderViewListAdapter (ArrayList<ListView.FixedViewInfo> headerViewInfos, 
                ArrayList<ListView.FixedViewInfo> footerViewInfos, 
                ListAdapter adapter)
Copy the code

AddHeaderView and addFootView are implemented by wrapping the existing adapter into a HeaderViewListAdapter.

FixedViewInfo

public class FixedViewInfo {
  / / view
  public View view;
  / / data
  public Object data;
  // Whether to select. Selectable state
  public boolean isSelectable;
}
Copy the code

Click on the event

// Normal click events
void setOnClickListener (View.OnClickListener l)

// item click event
void setOnItemClickListener (AdapterView.OnItemClickListener listener)

// item long click event
void setOnItemLongClickListener (AdapterView.OnItemLongClickListener listener)

// item selects the event
void setOnItemSelectedListener (AdapterView.OnItemSelectedListener listener)
Copy the code

Multiple entries

Often the items in a list are not exactly the same, and need to be mixed with different types of items.

Here are two methods: getViewTypeCount and getItemViewType

Two methods are implemented by default

We implement multiple entries by overriding these two methods in BaseAdapter

Tip: convertView will not work if you use position directly in the getView method. This will result in a distorted view.

Memory optimization

When you swipe the screen, items that the ListView disappears from the screen are destroyed, and new items that appear on the screen are created. Quick swiping of a large number of items that display too much content will cause memory to be recycled faster than the creation of item objects, causing oom memory to run out. To avoid this, ListView needs to be optimized for memory overcommitment.

The reuse entry

The getView() method is called every time an item is displayed on the screen. If a View object is created in this method every time, the OOM memory will run out, so reuse this View object. The getView method already caches this object the convertView parameter, so you just call it.

/** * returns the item display, which is a View object *@paramPosition The position of the entry *@paramConvertView entries reuse objects *@param parent
* @return* /
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = null;
  
  // If convertView is not empty, reuse it
    if (convertView == null) {
        view = View.inflate(MainActivity.this, R.layout.list_item, null);
    }else {
        view = convertView;
    }
  
    TextView text = (TextView) view.findViewById(R.id.text);
    text.setText("Current entry" + position);
    return view;
}
Copy the code

ViewHolder

FindViewById traverses the entire layout each time, which can affect the efficiency of the program, so you can create a ViewHolder class to store control references. Each Item then accesses the ViewHolder;

Key method setTag()

// Define the ViewHolder static class outside
static class ViewHolder
{
    public ImageView img;
    public TextView title;
    public TextView info;
}

// Then override getView
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if(convertView == null)
    {
        holder = new ViewHolder();
      
        convertView = mInflater.inflate(R.layout.list_item, null);
      
        holder.img = (ImageView)item.findViewById(R.id.img)
        holder.title = (TextView)item.findViewById(R.id.title);
        holder.info = (TextView)item.findViewById(R.id.info);
      
        convertView.setTag(holder);
    }else
    {
        holder = (ViewHolder)convertView.getTag();
    }
        holder.img.setImageResource(R.drawable.ic_launcher);
        holder.title.setText("Hello");
        holder.info.setText("World");
    }
                                                                                                
    return convertView;
}
Copy the code

RecyclerView is mandatory to use ViewHolder;

Select the schema

ListView actually supports multiple selection mode Settings

/** * No mode is selected */
public static final int CHOICE_MODE_NONE = 0;
/** * Single mode */
public static final int CHOICE_MODE_SINGLE = 1;
/** * Multi-select mode */
public static final int CHOICE_MODE_MULTIPLE = 2;
/** * The list allows multiple choices in a modal selection mode */
public static final int CHOICE_MODE_MULTIPLE_MODAL = 3;
Copy the code

Select mode by setting layout properties

android:choiceMode
Copy the code
Constant Value Description
multipleChoice 2 Multiselect mode
multipleChoiceModal 3 Multiple selection mode for blocking click events
none 0 The selected mode
singleChoice 1 Radio mode

Methods for selecting modes are in the AbsListView abstract class

boolean isItemChecked (int position)
// Check whether the item at the specified position is selected

void setItemChecked (int position, 
                boolean value)
// Set the item check

int getCheckedItemCount (a)
// The number of items selected

long[] getCheckedItemIds (a)
// only valid if the mode is not optional and (hasStableIds() == true)

int getCheckedItemPosition (a)
// Index of selected position (only available in radio mode)

SparseBooleanArray getCheckedItemPositions (a)
// Get the positions of all selected items

void clearChoices (a)
// Clear all selected items

int getChoiceMode (a)
// Select the mode

void setChoiceMode (int choiceMode)
// Set the selection mode
    
void setMultiChoiceModeListener (AbsListView.MultiChoiceModeListener listener)
// Multi-select listener
Copy the code

The selection mode must meet the following requirements:

  1. Set selection mode (radio mode by default)

  2. Item has no child controls to intercept focus

    android:focusable="false"
    Copy the code

Multiple selection mode for blocking click events

There are two ways to enter the multiple selection mode in this mode:

  1. Long press the item
  2. By function callsetItemChecked

GridView

Translation means “grid view”. The difference with ListView is the grid list.

Note, however, that the GridView is not a horizontal sliding layout, but a ListView that increases the number of columns. Horizontal sliding layout can be used HorizontalScrollView and RecyclerView GridLayoutManager layout

The GridView is compatible with all of the ListView’s adapters.

The layout properties

Each property has a corresponding method. Detailed introduction to see the method.

attribute describe
android:columnWidth Column width (invalid by default) needs to be used in conjunction with stretch mode
android:numColumns Number of columns (default 1)
android:stretchMode Stretching mode
android:horizontalSpacing Horizontal spacing
android:verticalSpacing The vertical distance between
android:gravity alignment

The sample

Use the same as ListView. Support for all of the ListAdapter adapters discussed earlier;

mList.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, title));

mList.setNumColumns(2); // Set the number of columns. Default 1. The same as ListView
Copy the code

Column width and spacing

A GridView is like a grid list. It is very important to learn how to arrange the grid.

The figure above illustrates the GridView’s column width and horizontal and vertical spacing

The width of the grid

// The width of the grid. Pixel unit
int getColumnWidth (a)
void setColumnWidth (int columnWidth)
Copy the code

Tip: If you set a fixed size in the layout of an item, this will result in clipping.

Stretching mode

Stretch mode is what I think is the most important and most difficult part of GridView to understand. Pay attention to understand my analysis

// Set the stretch mode
void setStretchMode (int stretchMode)
Copy the code

Four stretching modes are supported

  1. NO_STRETCH

    No stretching, size control yourself. The grid width must be set in this mode otherwise nothing will be displayed, right

  2. STRETCH_COLUMN_WIDTH

    By default, column width is determined by screen stretching. So the setColumnWidth described earlier is invalid. The grid content is scaled according to the screen size

  3. STRETCH_SPACING

    The mode must specify the column width or it will not display, and the self-specified spacing (both horizontal and vertical) is invalid

  4. STRETCH_SPACING_UNIFORM

    In this mode, the following widths and spacing are valid values, and the horizontal leftmost spacing is also available.

    However, since all values are valid, the effect of screen distribution cannot be achieved

Specify grid width (setColumnWidth) for all modes except STRETCH_COLUMN_WIDTH.

Conclusion:

  1. Stretch spacing or column width cannot be set.
  2. If the column width and spacing are not in stretch mode, it cannot be evenly distributed
  3. If you’re not stretching the column width you have to specify the column width or you don’t display the content.

spacing

// Set the horizontal interval
int getHorizontalSpacing (a)
void setHorizontalSpacing (int horizontalSpacing)

// Set the vertical interval
void setVerticalSpacing (int verticalSpacing)
int getVerticalSpacing (a)
Copy the code

The number of columns

void setNumColumns (int numColumns)
int getNumColumns (a)
Copy the code

alignment

int getGravity (a)
void setGravity (int gravity)
Copy the code

Methods to introduce

// Return the adapter
ListAdapter getAdapter (a)
Copy the code

Nested list

Here we introduce nesting between GridViews and ListViews or between two types of identical lists.

List nested problems fall into two categories:

  1. Display incomplete
  2. Nested lists cannot slide

The first kind of

If there is a nested list a highly to wrap_content | match_parent list when they found, according to list cannot be nested but this situation will happen if the height of the fixed, but many data are not fixed but by the number of dynamic load data.

Use custom onMeasure methods to give nested ListViews an unlimited maximum height

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
				MeasureSpec.AT_MOST);
		super.onMeasure(widthMeasureSpec, expandSpec);
	}
Copy the code

Integer has a maximum of 32 bits, shifted two to the right because the first two bits represent the schema in MeasureSpec

Private static final int MODE_SHIFT = 30;

// Int is 32 bits, moved 30 bits to the left. This attribute represents the mask value, and is used to “&” size and mode to obtain the corresponding value. private static final int MODE_MASK = 0x3 << MODE_SHIFT;

// Move 30 bits to the left, the value is 00… Public static final int UNSPECIFIED = 0 << MODE_SHIFT;

// Move 30 bits to the left, the value is 01… Public static final int EXACTLY = 1 << MODE_SHIFT;

// Move 30 bits to the left, the value is 10… Public static final int AT_MOST = 2 << MODE_SHIFT;

If you don’t want to override the ListView, dynamically set the ListView height by the number of items in the ListView

private void setListViewHeight(ListView listView) {

    ListAdapter listAdapter = listView.getAdapter();

    if (listAdapter == null) {    
            return;
    }

    int totalHeight = 0;

    for (int i = 0; i < listAdapter.getCount(); i++) {

            View listItem = listAdapter.getView(i, null, listView);
            listItem.measure(0.0);
            totalHeight += listItem.getMeasuredHeight();
    }


    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight
                    + (listView.getDividerHeight() * (listAdapter.getCount() - 1));

    listView.setLayoutParams(params);

}
Copy the code

Or you can set layoutParams for each View object in the getView method

The second,

The two approaches described above only address the problem of listViews not being displayed when nested. But if you have a nested ListView and you have a sliding ListView, you need to do something else.

In fact, Google has taken this problem into account and provided a method that works directly

ViewCompat.setNestedScrollingEnabled(mList,true); // Api21 can be used directly with View instead of ViewCompat
Copy the code

The second case does not occur with NestedScrollView and nested ListViews or GridViews in ScrollView, but incomplete displays can occur. Same solution.

The solution to the second method of nesting GridView and ListView in RecyclerView is invalid.

ExpandableListView

ExpandableListView is a ListView that supports group expansion.

There are two main parts: groups and sublists

Attributes

Indicator icon

android:groupIndicator

android:childIndicator
Copy the code

Indicator interval

android:indicatorEnd	
android:indicatorLeft	
android:indicatorRight	
android:indicatorStart

android:childIndicatorEnd	
android:childIndicatorLeft	
android:childIndicatorRight	
android:childIndicatorStart
Copy the code

The indicator icon will overlap with the contents of your getView() view. A padding is recommended for item

Sublist splitter

android:childDivider
Copy the code

The divider can be an image or a color. But it’s a full screen splitter at 1DP height anyway. The adapter isChildSelectable() method must return true.

Remove the default indicator and divider

android:divider="@null"
android:groupIndicator="@null"
Copy the code

ExpandableListAdapter

The ExpandaleListAdapter belongs to an interface. In general, the subclasses are used directly.

abstract boolean	areAllItemsEnabled(a)
  
// This method is used by the adapter to return view data
abstract Object	getChild(int groupPosition, int childPosition)

  
// Sublist item ID
abstract long	getChildId(int groupPosition, int childPosition)

// Sublist item view
abstract View	getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent)

/ / child list
abstract int	getChildrenCount(int groupPosition)


abstract long	getCombinedChildId(long groupId, long childId)


abstract long	getCombinedGroupId(long groupId)

/ / set of objects
abstract Object	getGroup(int groupPosition)

/ / group number
abstract int	getGroupCount(a)

/ / group id
abstract long	getGroupId(int groupPosition)

// Return to the group view
abstract View	getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent)

// If id is stable, this method is equivalent to ListView
abstract boolean	hasStableIds(a)

// Whether the sublist is optional
abstract boolean	isChildSelectable(int groupPosition, int childPosition)

abstract boolean	isEmpty(a)

// Group collapse callback
abstract void	onGroupCollapsed(int groupPosition)

// Group expansion callback
abstract void	onGroupExpanded(int groupPosition)
Copy the code

BaseExpandableListAdapter

Similar to BaseAdapter, the methods that need to be implemented have been described above. The following is a straightforward example;

public class CustomExpandableListAdapter extends BaseExpandableListAdapter {

    private  Context mContext;
    private  List<String> mGroupData;
    private  List<ArrayList<String>> mChildData;

    public CustomExpandableListAdapter(Context context, List<String> groupData, List<ArrayList<String>> childData) {
        mContext = context;
        mGroupData = groupData;
        mChildData = childData;
    }

    @Override public int getGroupCount(a) {
        return mGroupData.size();
    }

    @Override public int getChildrenCount(int i) {
        return mChildData.size();
    }

    @Override public Object getGroup(int i) {
        return mGroupData.get(i);
    }

    @Override public Object getChild(int i, int i1) {
        return mChildData.get(i).get(i1);
    }

    @Override public long getGroupId(int i) {
        return i;
    }

    @Override public long getChildId(int i, int i1) {
        return i+i1;
    }

    @Override public boolean hasStableIds(a) {
        return true;
    }

    @Override public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {

        if(view == null) {
        }

        View groupView = LayoutInflater.from(mContext).inflate(R.layout.item_group_text, viewGroup, false);
        TextView tvTitle = ButterKnife.findById(groupView, R.id.tv_title);
        tvTitle.setText(mGroupData.get(i));
        return groupView;
    }

    @Override public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
        View childView = LayoutInflater.from(mContext).inflate(R.layout.item_group_text, viewGroup, false);
        TextView tvTitle = ButterKnife.findById(childView, R.id.tv_title);
        tvTitle.setText(mChildData.get(i).get(i1));
        return childView;
    }

    @Override public boolean isChildSelectable(int i, int i1) {
        return true; }}Copy the code

SimpleExpandableListAdapter

SimpleExpandableListAdapter and SimpleAdapter almost does not belong to the abstract class, you just need to use the constructor to create instances.

SimpleExpandableListAdapter (Context context, List<? extends Map<String, ? >> groupData,/ / data
                int groupLayout,  // Group view layout
                String[] groupFrom, / / data key
                int[] groupTo,   // Layout control IDList<? extends List<? extends Map<String, ? >>> childData,int childLayout,  // Sublist view
                String[] childFrom, 
                int[] childTo) SimpleExpandableListAdapter (Context context, List<? extends Map<String, ? >> groupData,int expandedGroupLayout, // Rent the layout
                int collapsedGroupLayout, // Group folding layout
                String[] groupFrom, 
                int[] groupTo, List<? extends List<? extends Map<String, ? >>> childData,int childLayout, 
                String[] childFrom, 
                int[] childTo) SimpleExpandableListAdapter (Context context, List<? extends Map<String, ? >> groupData,int expandedGroupLayout, 
                int collapsedGroupLayout, 
                String[] groupFrom, 
                int[] groupTo, List<? extends List<? extends Map<String, ? >>> childData,int childLayout, 
                int lastChildLayout, // Rent the view of the last sublist
                String[] childFrom, 
                int[] childTo)
Copy the code

From a constructor can see SimpleExpandableListAdapter also supports two kinds of fixed kinds of layout. Note that the groupTo/childTo control IDS for multi-type layouts must still be included.

The listener

Sublist click events

void setOnChildClickListener (ExpandableListView.OnChildClickListener onChildClickListener)
Copy the code

Group click event

void setOnGroupClickListener (ExpandableListView.OnGroupClickListener onGroupClickListener)
Copy the code

Group shrink and expand events

void setOnGroupCollapseListener (ExpandableListView.OnGroupCollapseListener onGroupCollapseListener)

void setOnGroupExpandListener (ExpandableListView.OnGroupExpandListener onGroupExpandListener)
Copy the code

Unfolding and shrinking a group simply requires returning true in the callback of the group click event

        mExpand.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
            @Override
            public boolean onGroupClick(ExpandableListView expandableListView, View view, int i,
                    long l) {
                return true; }});Copy the code

Spinner

Although Spinner is a container layout, it does not support child controls. Because it inherits AdapterView;

Simple implementation

Create controls in the layout

<Spinner
         android:id="@+id/spinner"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:entries="@array/entries"
         />
Copy the code

Values /strings creates an array entity

<resources>
    <string-array name="entries">
        <item>Mercury</item>
        <item>Venus</item>
        <item>Earth</item>
        <item>Mars</item>
        <item>Jupiter</item>
        <item>Saturn</item>
        <item>Uranus</item>
        <item>Neptune</item>
    </string-array>
</resources>
Copy the code

Attributes

// Horizontal and vertical offset. Only vertical is valid
android:dropDownHorizontalOffset

android:dropDownVerticalOffset

android:dropDownWidth // Drop down the popover width

android:dropDownSelector // Drop down the color picker

android:gravity 

android:popupBackground // Drop down popover background color

android:spinnerMode // dialog box/dropdown popover

android:prompt // The title of the dialog mode. Note that string is referenced
Copy the code

Choose listening

mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
  @Override
  public void onItemSelected(AdapterView<? > parent, View view,int position, long id) {}@Override public void onNothingSelected(AdapterView
        parent) {}});Copy the code

If you just want to use drop-down lists you can look at ListPopupWindow; Simple drop down list, provide attachment function and custom width and height;