Android Support Design Library之TextInputLayout(一)

简介: Android Support Design Library之TextInputLayout(一)

相信普通的用户在使用手机的时候经常遇到一个输入框没输入的时候会有灰色的提示,可一旦输入些许字符后,用户很快忘记了这个输入框要输入什么,但是退回去却又要重新输入,对于用户的这个要求,谷歌看在眼里,在2015推出了TextInputLayout来满足这个需求。那么对于怎么使用这个控件,我将用模仿网易邮箱大师的登录界面来一一告诉大家怎么畅快的玩起来。


下面来看看,我们将要实现的界面。


48.png


1.TextInputLayout在布局里面的那些事


首先导入:

implementation 'com.android.support:design:29.0.0'

对于TextInputLayout并不能单独的使用,必须配合TextInputEditText使用起来。下面我们来看看登录界面的布局XML代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/lyj_layout"
    android:orientation="vertical">
    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/username_til"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/username_edit"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/login_username_edittext_string"/>
    </com.google.android.material.textfield.TextInputLayout>
    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/password_til"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/password_edit"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="textPassword"
            android:hint="@string/login_password_edittext_string"/>
    </com.google.android.material.textfield.TextInputlayout>
    <Button
        android:id="@+id/okbut"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="@string/login_okbut_string"/>
</LinearLayout>


上面只是简单的两个输入框EditText,与一个Button,唯一不同是EditText被TextInputLayout所包裹。这样我们的邮箱登录初始化界面就完成了。现在运行界面,我们就可以得到有动画效果的提示信息界面,如下:

50.png


2.实现网易邮箱提示信息


邮箱提示可以用android.support.v7.widget.ListPopupWindow来实现。它与ListView用法相同,也与PopupMenu,PopupWindow用法一样(此一样是说的其中的特性,不是完全)。


现在我们来初始化ListPopupWindow:


不过先还是写一下用到的所有成员变量:

private TextInputLayout usernameTil;//用户名输入框包裹的TextInputLayout
private TextInputLayout passwordTil;//密码输入框包裹的TextInputLayout
private TextInputEditText usernameEdit;//用户名输入框
private Button okBut;
private ListPopupWindow listPopupWindow;//输入框弹出菜单
private List<String> strLists = new ArrayList<>();//adatper参数
private List<String> strListsFlag = new ArrayList<>();//记录所有邮箱提示,当匹配后提示邮箱减少后可以直接从该list中重启获取添加到strLists;
private ArrayAdapter<String> adapter;//listpopupwindow适配器
private int numStartFlag = 0;//输入框的变化返回的永远是整个字符,要想字符加入提示框不重复,必须获取输入框@字符的索引
private int mLastNumFlag=0;//记录输入用户名后的前一次字符数,也就是输入是增加了还是减少了。
private boolean isHaveFlag=true;//记录删除用户名输入框的一个字符后,其还有匹配原来的邮箱吗?没有为false则需增加提示框邮箱。


后面的代码除方法外全部在onCreate()中:

this.listPopupWindow = new ListPopupWindow(this);//初始化
this.adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, strLists);
this.listPopupWindow.setAdapter(adapter);
this.listPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
this.listPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
this.listPopupWindow.setAnchorView(usernameTil);//设置弹出菜单相对谁的位置
this.listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        usernameEdit.setText(strLists.get(position));//当点击提示弹出菜单的时候,设置输入框与弹出菜单选项一致
        listPopupWindow.dismiss();//当然点击菜单后,关闭菜单
    }
});


适配器自不必说,setAnchor设置相对谁的位置。当然是我们的TextInputLayout,那么将会显示在其下面。当你输入一段输入到输入框的时候,点击ListPopupWindow中的选项,代码将会将选项写入到输入框,且这个时候也要关闭ListPopupWindow提示信息。


但是TextInputLayout虽然说可以直接从其获取他包裹的EditText的文本信息,可是其没有负责监听输入框变化的回调函数,故还是要获取EditText的控件进行操作。实现其监听如下:

this.usernameEdit.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        listPopupWindow.show();//当开始输入的时候弹出提示listPopupWindow
    }
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        listPopupWindowChanged(s);
    }
    @Override
    public void afterTextChanged(Editable s) {
    }
});


我们将提示算法分离出来写入listPopupWindowChanged(s)中,代码如下:

private void listPopupWindowChanged(CharSequence s) {
    //这就是大名鼎鼎的算法,我花了2个小时写的,只能说我算法不行啊。既然一个小小的匹配算法花了我2个小时
    //当输入框已经输入@符号后
    if (s.toString().indexOf('@') != -1) {
        //其实这里还可以判断一下@是不是文本框最后一个字符,判断后可以节省一个for循环时间。
        //比如当我输入"liyuanjinglyj@1"到输入框后,这个时候,凡是没有包含这个的提示listpopupwindow子项都会被删除
        for (int i = 0; i < strLists.size(); i++) {
            if (!strLists.get(i).trim().contains(s.toString().trim())) {
                strLists.remove(i);
                i--;//那么删除后strLists长度肯定减一,不然,不是匹配掉,就是数组越界。
            }
        }
        //当我在进行删去文本框字符的时候调用里面的方法,
        // 因为我输入的时候,要匹配我输入的邮箱,已经删除了以前的listpopupwindow子项,
        //这个时候我删除字符,那么以前因为匹配而删除的并且有匹配能的应该添加到listpopupwindow中
        if (s.toString().trim().length()<mLastNumFlag){
            for (int i = 0; i < strListsFlag.size(); i++) {
                if (strListsFlag.get(i).contains(s.toString().trim().substring(s.toString().indexOf('@')))) {
                    //当listpopupwindow有选项时
                    if(strLists.size()>0){
                        for (int j=0;j<strLists.size();j++){
                            if(strLists.get(j).contains(strListsFlag.get(i).substring(0))){
                                isHaveFlag=true;
                                break;
                            }
                            isHaveFlag=false;//如果里面没有该项,标记为false
                        }
                        if(!isHaveFlag){//这里判断添加
                            strLists.add(s.toString().trim().substring(0,s.toString().indexOf('@'))+strListsFlag.get(i));
                            isHaveFlag=true;
                        }
                    }else{//当listpopupwindow没有选项时
                        strLists.add(s.toString().trim().substring(0,s.toString().indexOf('@'))+strListsFlag.get(i));
                    }
                }
            }
        }
        //当其有@了的时候,我listpopupwindow提示依然只需要前面的字符串所以要截取@前面的字符串即可
        s = s.toString().substring(0, s.toString().indexOf('@'));
    }
    for (int i = 0; i < strLists.size(); i++) {
        strLists.set(i, s + strLists.get(i).substring(numStartFlag));//获取文本框字符加上邮箱后缀,得到提示。
    }
    numStartFlag = s.length();//保存邮箱格式的开始索引,为了让输入框不重复输入字符
    mLastNumFlag=usernameEdit.getText().toString().trim().length();//保存输入框文本长度
    adapter.notifyDataSetChanged();//更新弹出的listpopupwindow
}


对于这个算法,注释我写的已经很详细了。细节看注释。


不过这里还有一个问题,有必要说明一下,我的字符串数组是写在资源文件res/value/array.xml中的,但字符串数组string-array中<item>中并不能直接写入@符号,否则报错,可是加入转义符后虽然不报错,但是其连转义符一起写入了字符串,还是需要遍历,我百度了许久也没有看到解决方案,所以我干脆在代码遍历加入@。


这里暂且设置一个疑问,如果谁知道如何解决可以告诉我,回复在文章下面。


这里我的处理方式如下:

this.strLists = Arrays.asList(getResources().getStringArray(R.array.email_string_array));
this.strLists = new ArrayList<>(this.strLists);//上面解释了,如下不这样,那么匹配删除就是抛出上面的异常
//为什么还要循环添加@,而不写入资源文件
//是因为@在资源文件里面报错。具体怎么解决,我没有百度到,好像从来没人这么用。
for (int i = 0; i < this.strLists.size(); i++) {
    this.strLists.set(i, "@" + this.strLists.get(i));
}
this.strListsFlag = new ArrayList<>(this.strLists);//复制给保存弹出listpopupwindow,免得删除提示后无法恢复


为什么要strLists=new ArrayList<>(this.strLists)原因如下:


Arrays.asList() 返回java.util.Arrays$ArrayList,而不是ArrayList。Arrays$ArrayList和ArrayList都是继承AbstractList,remove,add等method在AbstractList中是默认throw UnsupportedOperationException而且不作任何操作,ArrayList 覆盖这些method来对list进行操作,但是Arrays$ArrayList没有覆盖 remove(),add()等,所以使用就会throw UnsupportedOperationException。

相关文章
|
6月前
|
存储 Java 数据库
Android数据存储:什么是Room Persistence Library?
Android数据存储:什么是Room Persistence Library?
125 0
|
2月前
|
XML Android开发 UED
💥Android UI设计新风尚!掌握Material Design精髓,让你的界面颜值爆表!🎨
随着移动应用市场的蓬勃发展,用户对界面设计的要求日益提高。为此,掌握由Google推出的Material Design设计语言成为提升应用颜值和用户体验的关键。本文将带你深入了解Material Design的核心原则,如真实感、统一性和创新性,并通过丰富的组件库及示例代码,助你轻松打造美观且一致的应用界面。无论是色彩搭配还是动画效果,Material Design都能为你的Android应用增添无限魅力。
68 1
|
3月前
|
开发工具 Android开发
解决Android运行出现NDK at /Library/Android/sdk/ndk-bundle did not have a source.properties file
解决Android运行出现NDK at /Library/Android/sdk/ndk-bundle did not have a source.properties file
168 4
解决Android运行出现NDK at /Library/Android/sdk/ndk-bundle did not have a source.properties file
|
4月前
|
XML Android开发 UED
💥Android UI设计新风尚!掌握Material Design精髓,让你的界面颜值爆表!🎨
【7月更文挑战第28天】随着移动应用市场的发展,用户对界面设计的要求不断提高。Material Design是由Google推出的设计语言,强调真实感、统一性和创新性,通过模拟纸张和墨水的物理属性创造沉浸式体验。它注重色彩、排版、图标和布局的一致性,确保跨设备的统一视觉风格。Android Studio提供了丰富的Material Design组件库,如按钮、卡片等,易于使用且美观。
152 1
|
Android开发 开发者 UED
Android Design Support Library初探-更新中
Android Design Support Library初探-更新中
98 0
|
XML Java 开发工具
Android5.0新特性-Material Design
Android5.0新特性-Material Design
93 0
|
4天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
9天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。