1.关于coordinatorLayout

CoordinatorLayout简介

CoordinatorLayout是在 Google IO/15 大会发布的,遵循Material 风格,包含在 support Library中,结合AppbarLayout, CollapsingToolbarLayout等 可 产生各种炫酷的效果

简单来说就是

  • 作为最上层的View
  • 作为一个 容器与一个或者多个子View进行交互
AppBarLayout
与AppbarLayout组合的滚动布局(RecyclerView, NestedScrollView等),需要设置 app:layout_behavior = "@string/appbar_scrolling_view_behavior" .没有设置的话, AppbarLayout将不会响应滚动布局的滚动事件.
类型 说明
int SCROLL_FLAG_ENTER_ALWAYS When entering (scrolling on screen) the view will scroll on any downwards scroll event, regardless of whether the scrolling view is also scrolling.
int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED An additional flag for 'enterAlways' which modifies the returning view to only initially scroll back to it's collapsed height.
int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED When exiting (scrolling off screen) the view will be scrolled until it is 'collapsed'.
int SCROLL_FLAG_SCROLL The view will be scroll in direct relation to scroll events.
int SCROLL_FLAG_SNAP Upon a scroll ending, if the view is only partially visible then it will be snapped and scrolled to it's closest edge.
类型 说明
int SCROLL_FLAG_ENTER_ALWAYS W((entering) / (scrolling on screen))下拉的时候,这个View也会跟着滑出。
int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED 另一种enterAlways,但是只显示折叠后的高度。
int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED ((exiting) / (scrolling off screen))上拉的时候,这个View会跟着滑动直到折叠。
int SCROLL_FLAG_SCROLL 这个View将会响应Scroll事件
int SCROLL_FLAG_SNAP 在Scroll滑动事件结束以前 ,如果这个View部分可见,那么这个View会停在最接近当前View的位置

我们可以通过两种 方法设置这个Flag

  • 方法一
 setScrollFlags(int)
  • 方法二
 app:layout_scrollFlags="scroll|enterAlways"

注意事项

AppBarLayout必须作为CoordinatorLayout的直接子View,否则它的大部分功能将不会生效,如layout_scrollFlags等。


CollapsingToolbarLayout

CollapsingToolbarLayout继承与FrameLayout,官网地址,请自备梯子。

简单来说 ,CollapsingToolbarLayout是工具栏的包装器,它通常作为AppBarLayout的孩子。主要实现以下功能

  • Collapsing title(可以折叠 的 标题 )
  • Content scrim(内容装饰),当我们滑动的位置 到达一定阀值的时候,内容 装饰将会被显示或者隐藏
  • Status bar scrim(状态栏布)
  • Parallax scrolling children,滑动的时候孩子呈现视觉特差效果
  • Pinned position children,固定位置的 孩子

下面我们一起来看一下几个常量

常量 解释说明
int COLLAPSE_MODE_OFF The view will act as normal with no collapsing behavior.(这个 View将会 呈现正常的结果,不会表现出折叠效果)
int COLLAPSE_MODE_PARALLAX The view will scroll in a parallax fashion. See setParallaxMultiplier(float) to change the multiplier used.(在滑动的时候这个View 会呈现 出 视觉特差效果 )
int COLLAPSE_MODE_PIN The view will pin in place until it reaches the bottom of the CollapsingToolbarLayout.(当这个View到达 CollapsingToolbarLayout的底部的时候,这个View 将会被放置,即代替整个CollapsingToolbarLayout)

我们有两种方法可以设置这个常量,

方法一:在代码中使用这个方法

setCollapseMode(int collapseMode)

方法 二:在布局文件中使用自定义属性

app:layout_collapseMode="pin"


DrawerLayout 简单使用

介绍

drawerLayout是Support Library包中实现了侧滑菜单效果的控件,可以说drawerLayout是因为第三方控件如MenuDrawer等的出现之后,google借鉴而出现的产物。drawerLayout分为侧边菜单和主内容区两部分,侧边菜单可以根据手势展开与隐藏(drawerLayout自身特性),主内容区的内容可以随着菜单的点击而变化(这需要使用者自己实现)。

实用

DrawerLayout 实用比较简单,这里只介绍简单使用和常用API。

  1. 在布局文件中使用DrawerLayout 进行设置。如下示例代码:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dlyt_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    ><!-- 内容 --><FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"><Button
            android:id="@+id/btn_context"
            android:text="context"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" /></FrameLayout><!-- 左边菜单 --><FrameLayout
        android:background="@color/colorAccent"
        android:layout_gravity="start"
        android:layout_width="200dp"
        android:layout_height="match_parent"><Button
            android:id="@+id/btn_left_menu"
            android:text="left menu"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" /></FrameLayout><!-- 右边菜单 --><FrameLayout
        android:background="@color/colorAccent"
        android:layout_gravity="end"
        android:layout_width="200dp"
        android:layout_height="match_parent"><Button
            android:id="@+id/btn_right_menu"
            android:text="right menu"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" /></FrameLayout>
</android.support.v4.widget.DrawerLayout>

在 DrawerLayout 布局中有三个元素,

  1. view 主体
  2. 左边菜单:
    左边菜单的设定使用android:layout_gravity="start" 设置。
  3. 右边菜单:
    右边菜单的设定使用android:layout_gravity="end" 设置。

通过上面,我们就已经实现了左右划出菜单效果。
如果我们需要加上一些控制逻辑,可能就需要一些的一些API了。

DrawerLayout 中部分 API 介绍

  1. isDrawerOpen(@EdgeGravity int drawerGravity) : 判断菜单是否打开。

传入参数:

  • GravityCompat.START : 左边菜单是否打开。
  • GravityCompat.END : 右边菜单是否打开。

返回值

  • 打开 : true
  • 关闭 : false
  1. openDrawer(@EdgeGravity int gravity) : 打开菜单

传入参数:

  • GravityCompat.START : 打开左边菜单。
  • GravityCompat.END : 打开右边菜单。
  1. closeDrawer(@EdgeGravity int gravity) : 关闭菜单

传入参数:

  • GravityCompat.START : 关闭左边菜单。
  • GravityCompat.END : 关闭右边菜单。
  1. addDrawerListener(@NonNull DrawerListener listener) : 添加监听
  2. DrawerListener 类
  • onDrawerSlide(View drawerView, float slideOffset) : 滑动时调用
  • onDrawerOpened(View drawerView) : 打开菜单时调用
  • onDrawerClosed(View drawerView) : 关闭菜单时调用
  • onDrawerStateChanged(@State int newState) : 菜单状态改变时调用

其他API查看源码就会明白如何使用。

如下Java示例代码:

//添加监听
DrawerLayout.addDrawerListener(new DrawerViewListener());
private class DrawerViewListener implements DrawerLayout.DrawerListener {@Overridepublic void onDrawerSlide(View drawerView, float slideOffset) {//滑动时调用}@Overridepublic void onDrawerOpened(View drawerView) {//打开菜单时调用}@Overridepublic void onDrawerClosed(View drawerView) {//关闭菜单时调用}@Overridepublic void onDrawerStateChanged(int newState) {//菜单状态改变时调用}
}

AutoCompleteTextView

AutoCompleteTextView常用属性

属性 描述
android:completionHint 设置出现在下拉菜单底部的提示信息
android:completionThreshold 设置触发补全提示信息的字符个数
android:dropDownHorizontalOffset 设置下拉菜单于文本框之间的水平偏移量
android:dropDownHeight 设置下拉菜单的高度
android:dropDownWidth 设置下拉菜单的宽度
android:singleLine 设置单行显示文本内容
android:dropDownVerticalOffset 设置下拉菜单于文本框之间的垂直偏移量

使用ArrayAdapter来作为AutoCompleteTextView的数据适配器

  • 简单的xml布局
<AutoCompleteTextView
    android:id="@+id/tv_search"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/hint_type"
    android:completionHint="@string/chint_recent"
    android:completionThreshold="1" />
  • 默认AutoCompleteTextView中的数据保存在SharedPreferences中,故将SharedPreferences做了简单的API封装以方便数据存取,详细的SharedPreferences请参考这里:SharedPreferences
// 从SharedPreferences中获取历史记录数据
private String getHistoryFromSharedPreferences(String key) {SharedPreferences sp = getSharedPreferences(SP_NAME, MODE_PRIVATE);return sp.getString(key, SP_EMPTY_TAG);
}// 将历史记录数据保存到SharedPreferences中
private void saveHistoryToSharedPreferences(String key, String history) {SharedPreferences sp = getSharedPreferences(SP_NAME, MODE_PRIVATE);SharedPreferences.Editor editor = sp.edit();editor.putString(key, history);editor.apply();
}// 清除保存在SharedPreferences中的历史记录数据
private void clearHistoryInSharedPreferences() {SharedPreferences sp = getSharedPreferences(SP_NAME, MODE_PRIVATE);SharedPreferences.Editor editor = sp.edit();editor.clear();editor.apply();
}
  • 使用默认适配器的AutoCompleteTextView相关初始化
private void initSearchView() {mSearchTv = (AutoCompleteTextView) findViewById(R.id.tv_search);String[] mSearchHistoryArray = getHistoryArray(SP_KEY_SEARCH);mSearchAdapter = new ArrayAdapter<>(this,android.R.layout.simple_dropdown_item_1line,mSearchHistoryArray);mSearchTv.setAdapter(mSearchAdapter);  // 设置适配器// 设置下拉提示框的高度为200dp// mAutoCompleteTv.setDropDownHeight();      // 或XML中为android:dropDownHeight="200dp"// 默认当输入2个字符以上才会提示, 现在当设置输入1个字符就自动提示// mAutoCompleteTv.setThreshold(1);          // 或XML中为android:completionThreshold="1"// 设置下拉提示框中底部的提示// mAutoCompleteTv.setCompletionHint("最近的5条记录");// 设置单行输入限制// mAutoCompleteTv.setSingleLine(true);
}private String[] getHistoryArray(String key) {String[] array = getHistoryFromSharedPreferences(key).split(SP_SEPARATOR);if (array.length > MAX_HISTORY_COUNT) {         // 最多只提示最近的50条历史记录String[] newArray = new String[MAX_HISTORY_COUNT];System.arraycopy(array, 0, newArray, 0, MAX_HISTORY_COUNT); // 实现数组间的内容复制}return array;
}
  • 保存AutoCompleteTextView中的历史记录数据到SharedPreferences中
private void saveSearchHistory() {String text = mSearchTv.getText().toString().trim();       // 获取搜索框文本信息if (TextUtils.isEmpty(text)) {                      // null or ""Toast.makeText(this, "Please type something again.", Toast.LENGTH_SHORT).show();return;}String old_text = getHistoryFromSharedPreferences(SP_KEY_SEARCH);// 获取SP中保存的历史记录StringBuilder sb;if (SP_EMPTY_TAG.equals(old_text)) {sb = new StringBuilder();} else {sb = new StringBuilder(old_text);}sb.append(text + SP_SEPARATOR);      // 使用逗号来分隔每条历史记录// 判断搜索内容是否已存在于历史文件中,已存在则不再添加if (!old_text.contains(text + SP_SEPARATOR)) {saveHistoryToSharedPreferences(SP_KEY_SEARCH, sb.toString());  // 实时保存历史记录mSearchAdapter.add(text);        // 实时更新下拉提示框中的历史记录Toast.makeText(this, "Search saved: " + text, Toast.LENGTH_SHORT).show();} else {Toast.makeText(this, "Search existed: " + text, Toast.LENGTH_SHORT).show();}
}

上面代码中,为了能够实时更新下拉提示框中的历史记录,需要在保存数据后再调用ArrayAdapter.add()方法,而不是调用ArrayAdapter.notifyDataSetChanged()

  • 实时清除下拉提示框中的历史记录
clearHistoryInSharedPreferences();          // 试试清除历史记录
mSearchAdapter.clear();                     // 实时清除下拉提示框中的历史记录
  • 效果演示
arrayadapter_autocomplete_textview_320x512.gif


使用自定义AutoCompleteAdapter来作为AutoCompleteTextView的数据适配器

  • 简单的xml布局

使用RelativeLayout来容纳AutoCompleteTextView和ImageView,其中ImageView位于右侧,用于点击清除AutoCompleteTextView的内容

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:gravity="center_vertical"><AutoCompleteTextView
        android:id="@+id/tv_custom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingStart="12dp"
        android:paddingEnd="40dp"
        android:hint="@string/hint_type"/><ImageView
        android:id="@+id/iv_custom"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_marginEnd="10dp"
        android:layout_alignParentEnd="true"
        android:layout_centerVertical="true"
        android:scaleType="fitCenter"
        android:src="@drawable/ic_action_name"
        android:contentDescription="@null"/>
</RelativeLayout>
  • 使用自定义适配器的AutoCompleteTextView相关初始化
private void initCustomView() {mCustomTv = (AutoCompleteTextView) findViewById(R.id.tv_custom);mDeleteIv = (ImageView) findViewById(R.id.iv_custom);mDeleteIv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mCustomTv.setText("");              // 清空TextView的内容}});ArrayList<String> mOriginalValues = new ArrayList<>();String[] mCustomHistoryArray = getHistoryArray(SP_KEY_CUSTOM);mOriginalValues.addAll(Arrays.asList(mCustomHistoryArray));     // String[] => ArrayList<String>mCustomAdapter = new AutoCompleteAdapter(this, mOriginalValues);mCustomAdapter.setDefaultMode(AutoCompleteAdapter.MODE_STARTSWITH | AutoCompleteAdapter.MODE_SPLIT);// 设置匹配模式mCustomAdapter.setSupportPreview(true);     // 支持使用特殊符号进行预览提示内容,默认为'@'simpleItemHeight = mCustomAdapter.getSimpleItemHeight();Toast.makeText(this, "simpleItemHeight: " + simpleItemHeight, Toast.LENGTH_SHORT).show(); // 103mCustomAdapter.setOnFilterResultsListener(new AutoCompleteAdapter.OnFilterResultsListener() {@Overridepublic void onFilterResultsListener(int count) {curCount = count;if (count > MAX_ONCE_MATCHED_ITEM) {        // 限制提示框最多要显示的记录行数curCount = MAX_ONCE_MATCHED_ITEM;}if (curCount != prevCount) {                // 仅当目前的数目和之前的不同才重新设置下拉框高度,避免重复设置prevCount = curCount;mCustomTv.setDropDownHeight(simpleItemHeight * curCount);}}});mCustomAdapter.setOnSimpleItemDeletedListener(new AutoCompleteAdapter.OnSimpleItemDeletedListener() {@Overridepublic void onSimpleItemDeletedListener(String value) {String old_history = getHistoryFromSharedPreferences(SP_KEY_CUSTOM);    // 获取之前的记录String new_history = old_history.replace(value + SP_SEPARATOR, "");    // 用空字符串替换掉要删除的记录saveHistoryToSharedPreferences(SP_KEY_CUSTOM, new_history);             // 保存修改过的记录}});mCustomTv.setAdapter(mCustomAdapter);       //mCustomTv.setThreshold(1);                  //// 设置下拉时显示的提示行数 (此处不设置也可以,因为在AutoCompleteAdapter中有专门的事件监听来实时设置提示框的高度)// mCustomTv.setDropDownHeight(simpleItemHeight * MAX_ONCE_MATCHED_ITEM);
}
  • 保存AutoCompleteTextView中的历史记录数据到SharedPreferences中
private void saveCustomHistory() {String text = mCustomTv.getText().toString().trim();     // 获取搜索框信息if (TextUtils.isEmpty(text)) {          // null or ""Toast.makeText(this, "Please type something again.", Toast.LENGTH_SHORT).show();return;}String old_text = getHistoryFromSharedPreferences(SP_KEY_CUSTOM);    // 获取SP中保存的历史记录StringBuilder sb;if (SP_EMPTY_TAG.equals(old_text)) {sb = new StringBuilder();} else {sb = new StringBuilder(old_text);}sb.append(text + SP_SEPARATOR);      // 使用逗号来分隔每条历史记录// 判断搜索内容是否已存在于历史文件中,已存在则不再添加if (!old_text.contains(text + SP_SEPARATOR)) {saveHistoryToSharedPreferences(SP_KEY_CUSTOM, sb.toString());  // 实时保存历史记录mCustomAdapter.add(text);        // 实时更新下拉提示框中的历史记录Toast.makeText(this, "Custom saved: " + text, Toast.LENGTH_SHORT).show();} else {Toast.makeText(this, "Custom existed: " + text, Toast.LENGTH_SHORT).show();}
}
  • 实时清除下拉提示框中的历史记录
clearHistoryInSharedPreferences();      // 试试清除历史记录
mCustomAdapter.clear();                 // 实时清除下拉提示框中的历史记录
  • 自定义适配器AutoCompleteAdapter

AutoCompleteAdapter参考了ArrayAdapter的部分源代码,继承自BaseAdapter并实现Filterable接口,实现了以下功能:

  1. 实现自动补全的匹配模式的配置,有三种可选匹配模式:
MODE_CONTAINS / MODE_STARTSWITH(default) / MODE_SPLIT
  1. 实现匹配成功事件的回调,用于根据匹配结果数来动态设置下拉提示框的高度
  2. 实现删除匹配结果中子项的事件回调,用于实时更新存储在SharedPreferences的历史记录数据
  3. 支持使用@字符来预览所有提示内容
public class AutoCompleteAdapter extends BaseAdapter implements Filterable {private static final int MODE_NONE = 0x000;                 // 0000bpublic static final int MODE_CONTAINS = 0x001;              // 0001bpublic static final int MODE_STARTSWITH = 0x002;            // 0010bpublic static final int MODE_SPLIT = 0x004;                 // 0100bprivate static final String SPLIT_SEPARATOR = "[,.\\s]+";  // 分隔符,默认为空白符、英文逗号、英文句号private static boolean isFound = false;   // 当MODE_STARTSWITH模式匹配成功时,不再进行MODE_SPLIT模式的匹配private int defaultMode = MODE_STARTSWITH;                  // 0110bprivate LayoutInflater inflater;private ArrayFilter mArrayFilter;private ArrayList<String> mOriginalValues;      // 所有的itemprivate List<String> mObjects;                  // 过滤后的itemprivate final Object mLock = new Object();      // 同步锁private int maxMatch = 10;                      // 最多显示的item数目,负数表示全部private int simpleItemHeight;                   // 单行item的高度值,故需要在XML中固定父布局的高度值private char previewChar = '@';                 // 默认字符private boolean isSupportPreview = false;       // 是否可以使用@符号进行预览全部提示内容public AutoCompleteAdapter(Context context, ArrayList<String> mOriginalValues) {this(context, mOriginalValues, -1);}public AutoCompleteAdapter(Context context, ArrayList<String> mOriginalValues, int maxMatch) {this.mOriginalValues = mOriginalValues;// 初始化时将其设置成mOriginalValues,避免在未进行数据保存时执行删除操作导致程序的崩溃this.mObjects = mOriginalValues;   this.maxMatch = maxMatch;inflater = LayoutInflater.from(context);initViewHeight();}private void initViewHeight() {View view = inflater.inflate(R.layout.simple_dropdown_item_1line, null);LinearLayout linearLayout = (LinearLayout) view.findViewById(R.id.layout_item);linearLayout.measure(0, 0);// 其他方法获取的高度值会因View尚未被绘制而获取到0simpleItemHeight = linearLayout.getMeasuredHeight();}public int getSimpleItemHeight() {return simpleItemHeight;                // 5 * 2 + 28(dp) => 103(px)}public void setSupportPreview(boolean isSupportPreview){this.isSupportPreview = isSupportPreview;}public void setSupportPreview(boolean isSupportPreview, char previewChar){this.isSupportPreview = isSupportPreview;this.previewChar = previewChar;}@Overridepublic int getCount() {return mObjects.size();}@Overridepublic Object getItem(int position) {return mObjects.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {ViewHolder holder;if (convertView == null) {holder = new ViewHolder();convertView = inflater.inflate(R.layout.simple_dropdown_item_1line, null);holder.tv = (TextView) convertView.findViewById(R.id.tv_simple_item);holder.iv = (ImageView) convertView.findViewById(R.id.iv_simple_item);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}holder.tv.setText(mObjects.get(position));holder.iv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String value = mObjects.remove(position);if (mDeleteListener != null) {mDeleteListener.onSimpleItemDeletedListener(value);}if (mFilterListener != null) {mFilterListener.onFilterResultsListener(mObjects.size());}mOriginalValues.remove(value);notifyDataSetChanged();}});return convertView;}private static class ViewHolder {TextView tv;ImageView iv;}public void setDefaultMode(int defaultMode) {this.defaultMode = defaultMode;}public void add(String item) {mOriginalValues.add(item);notifyDataSetChanged();         //}public void clear() {if(mOriginalValues != null && !mOriginalValues.isEmpty()) {mOriginalValues.clear();notifyDataSetChanged();         //}}// Interfacepublic interface OnSimpleItemDeletedListener {void onSimpleItemDeletedListener(String value);}private OnSimpleItemDeletedListener mDeleteListener;public void setOnSimpleItemDeletedListener(OnSimpleItemDeletedListener listener) {this.mDeleteListener = listener;}// Interfacepublic interface OnFilterResultsListener {void onFilterResultsListener(int count);}private OnFilterResultsListener mFilterListener;public void setOnFilterResultsListener(OnFilterResultsListener listener) {this.mFilterListener = listener;}@Overridepublic Filter getFilter() {if (mArrayFilter == null) {mArrayFilter = new ArrayFilter(mFilterListener);}return mArrayFilter;}private class ArrayFilter extends Filter {private OnFilterResultsListener listener;public ArrayFilter(OnFilterResultsListener listener) {this.listener = listener;}@Overrideprotected FilterResults performFiltering(CharSequence prefix) {FilterResults results = new FilterResults();if (mOriginalValues == null) {synchronized (mLock) {mOriginalValues = new ArrayList<>(mObjects);}}if (prefix == null || prefix.length() == 0) {synchronized (mLock) {ArrayList<String> list = new ArrayList<>(mOriginalValues);results.values = list;results.count = list.size();}} else {if (isSupportPreview) {int index = prefix.toString().indexOf(String.valueOf(previewChar));if (index != -1) {prefix = prefix.toString().substring(index + 1);}}String prefixString = prefix.toString().toLowerCase();      // prefixStringfinal int count = mOriginalValues.size();                   // countfinal ArrayList<String> newValues = new ArrayList<>(count); // newValuesfor (int i = 0; i < count; i++) {final String value = mOriginalValues.get(i);            // valuefinal String valueText = value.toLowerCase();           // valueText// 1. 匹配所有if ((defaultMode & MODE_CONTAINS) != MODE_NONE) {if (valueText.contains(prefixString)) {newValues.add(value);}} else {    // support: defaultMode = MODE_STARTSWITH | MODE_SPLIT// 2. 匹配开头if ((defaultMode & MODE_STARTSWITH) != MODE_NONE) {if (valueText.startsWith(prefixString)) {newValues.add(value);isFound = true;}}// 3. 分隔符匹配,效率低if (!isFound && (defaultMode & MODE_SPLIT) != MODE_NONE) {final String[] words = valueText.split(SPLIT_SEPARATOR);for (String word : words) {if (word.startsWith(prefixString)) {newValues.add(value);break;}}}if(isFound) {   // 若在MODE_STARTSWITH模式中匹配,则再次复位进行下一次判断isFound = false;}}if (maxMatch > 0) {             // 限制显示item的数目if (newValues.size() > maxMatch - 1) {break;}}} // for (int i = 0; i < count; i++)results.values = newValues;results.count = newValues.size();}return results;}@Overrideprotected void publishResults(CharSequence constraint, FilterResults results) {//noinspection uncheckedmObjects = (List<String>) results.values;if (results.count > 0) {// 由于当删除提示框中的记录行时,而AutoCompleteTextView此时内容又不改变,故不会触发FilterResults事件// 导致删除记录行时,提示框的高度不会发生相应的改变// 解决方法:需要在ImageView的点击监听器中也调用OnFilterResultsListener.onFilterResultsListener()// 来共同完成if (listener != null) {listener.onFilterResultsListener(results.count);}notifyDataSetChanged();} else {notifyDataSetInvalidated();}}}
}
  • 下拉提示框的item布局simple_dropdown_item_1line.xml

这里需要固定父类控件LinearLayout的高度,在AutoCompleteAdapter中会获取其高度用于设置AutoCompleteTextView的下拉菜单的高度

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout_item"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="28dp"
    android:padding="5dp"
    android:gravity="center_vertical"><TextView
        android:id="@+id/tv_simple_item"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:paddingStart="5dp"
        android:paddingEnd="0dp"
        android:text="@string/text_nothing"
        android:textAllCaps="false"
        android:textSize="18sp"
        android:textColor="#000"/><ImageView
        android:id="@+id/iv_simple_item"
        android:layout_width="18dp"
        android:layout_height="18dp"
        android:layout_marginEnd="5dp"
        android:src="@drawable/ic_action_name"
        android:contentDescription="@null"
        android:scaleType="fitCenter" />
</LinearLayout>
  • 效果演示
  • 支持使用@字符来预览所有提示内容
android新特性:TextInputLayout使用方法
ConstraintLayout(约束布局)
写给小白——recyclerview的基本使用(毫无杂质版)中文文档
https://www.cnblogs.com/anni-qianqian/p/6587329.html
触摸反馈(波纹效果Ripple
android:theme和app:popupTheme的作用,以及在android 3.0以下不起作用问题的解决

关于Layout的总结。相关推荐

  1. android layout组件,Android UI学习 - Linear Layout, RelativeLayout

    1.一些常用的公共属性介绍 1) layout_width -宽 fill_parent: 宽度和父元素相同,wrap_content: 宽度随本身的内容所调整,或者指定 px值来设置宽 2) lay ...

  2. android的布局流程,Android View 布局流程(Layout)全面解析

    前言 上一篇文章,笔者详细讲述了View三大工作流程的第一个,Measure流程,如果对测量流程还不熟悉的读者可以参考一下上一篇文章.测量流程主要是对View树进行测量,获取每一个View的测量宽高, ...

  3. 更新pcb封装导入_教你如何将 AD 或 PADS 的原理图导入 Allegro 做 Layout

    作为allegro专业layout的我们,由于设计软件的限制,有时候客户提供的原理图可能是AD或Power Logic绘制的,而AD或Power Logic的原理图转成orcad原理图后可能存在丢失网 ...

  4. android layout analyze

    adapter api entity handler ui until widget appContent.java ************************************* 图片: ...

  5. iOS SwiftUI篇-3 排版布局layout

    iOS SwiftUI篇-3 排版布局layout swiftUI提供的layout有: ZStack.GeometryReader.HStack.LazyVGrid.LazyHStack.LazyH ...

  6. xx.xib: error: Illegal Configuration: Safe Area Layout Guide before iOS 9.0报错问题解决

    之前是用xcode8.3.3创建的工程最近升级到Xcode9.0 遇见了这个问题 在Xcode 9.0以上 新建xib文件会报错 xx.xib: error: Illegal Configuratio ...

  7. enyo官方开发入门教程翻译一Layout之Fittables

    Fittables Fittable包帮助你创建布局更合理的使用可用空间(app都有这样的布局需求,但使用以前的web技术很难做到这一点).个人观点,现在移动Web开发框架中有很多都支持自适应布局,如 ...

  8. O - Layout POJ - 3169(差分约束)

    O - Layout POJ - 3169 参考 思路: 限制条件 : 最大距离不超过w d[v] - d[u] <= w; 最小距离超过w d[v] - d[u] >= w; 移项得 d ...

  9. 移动端适配之二:visual viewport、layout viewport和ideal viewport介绍

    上一篇博文,可算把像素这个东西讲清楚了.在这篇博文里面,将继续介绍viewport相关的内容. 很多博客都会提到PPK所讲的三个viewport,有的讲的比较复杂,看的云里雾里,我这里也大概介绍一下, ...

  10. Springboot 使用thymeleaf模板layout布局

    使用layout布局前应该在pom文件中导入thymeleaf(dialect)依赖:如下 <properties><project.build.sourceEncoding> ...

最新文章

  1. 限时福利:腾讯高级专家手把手教你打造 OCR 神器!
  2. Java Spring实现原理研究之Servlet initialization初始化过程
  3. Vue父组件使用子组件时,需要携带参数,函数内如何获取子组件给的值
  4. Struts2中s:iterator/s:iterator标签的使用:
  5. python帮助文档在哪_python文档在哪里
  6. java导出富文本到word_富文本编辑器内容实现word导出下载,请各位大神们指点,感激不尽...
  7. 计算机专业个人能力评估,计算机应用专业毕业生个人自我评价
  8. 创建mysql用户并在单个数据库上赋权
  9. mysql双机热备的配置步骤
  10. cygwin下各盘挂载点
  11. blender_(uv应用)................http://digitalman.blog.163.com/blog/static/23874605620174172058299/...
  12. 工具类记录之Guawa的Splitter
  13. 虚拟摄像头之DirectShow虚拟摄像头开发
  14. JavaScript学习笔记(6)变量
  15. 【Java】一个公司职员薪水管理系统(顺序表)
  16. 周末作业-循环练习题(2)
  17. Oracle--ORA-01775: 同义词的循环链
  18. 【c语言中的运算符】
  19. 日志规范——转自晓风轻专栏
  20. 搭建注册中心Eureka运行时报错:[ main] o.s.b.d.LoggingFailureAnalysisReporter :

热门文章

  1. pandas 文档自用3
  2. 文心一言 VS 讯飞星火 VS chatgpt (43)-- 算法导论5.4 7题
  3. Net-a-Porter Coach factory outlet
  4. 爱上一个叫史今的男人
  5. 面试6轮才发offer,拒绝入职后,竟被HR索赔2万元违约金,理由是“浪费公司时间和人力成本!”...
  6. xp系统文件夹无法访问拒绝访问解决方法
  7. Excel插件制作-面积图系列
  8. 解决英伟达Jetson平台使用Python时的出现“Illegal instruction(cpre dumped)”错误
  9. 为什么64位计算机CPU架构叫amd64
  10. Unity特殊文件夹