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?
115 0
|
2月前
|
XML Android开发 UED
💥Android UI设计新风尚!掌握Material Design精髓,让你的界面颜值爆表!🎨
随着移动应用市场的蓬勃发展,用户对界面设计的要求日益提高。为此,掌握由Google推出的Material Design设计语言成为提升应用颜值和用户体验的关键。本文将带你深入了解Material Design的核心原则,如真实感、统一性和创新性,并通过丰富的组件库及示例代码,助你轻松打造美观且一致的应用界面。无论是色彩搭配还是动画效果,Material Design都能为你的Android应用增添无限魅力。
52 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
156 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组件库,如按钮、卡片等,易于使用且美观。
128 1
|
Android开发 开发者 UED
Android Design Support Library初探-更新中
Android Design Support Library初探-更新中
96 0
|
XML Java 开发工具
Android5.0新特性-Material Design
Android5.0新特性-Material Design
90 0
android.support.v4.app.Fragment$InstantiationException问题解决
android.support.v4.app.Fragment$InstantiationException问题解决
|
22天前
|
缓存 搜索推荐 Android开发
安卓开发中的自定义控件实践
【10月更文挑战第4天】在安卓开发的海洋中,自定义控件是那片璀璨的星辰。它不仅让应用界面设计变得丰富多彩,还提升了用户体验。本文将带你探索自定义控件的核心概念、实现过程以及优化技巧,让你的应用在众多竞争者中脱颖而出。
|
22天前
|
Java Android开发 Swift
安卓与iOS开发对比:平台选择对项目成功的影响
【10月更文挑战第4天】在移动应用开发的世界中,选择合适的平台是至关重要的。本文将深入探讨安卓和iOS两大主流平台的开发环境、用户基础、市场份额和开发成本等方面的差异,并分析这些差异如何影响项目的最终成果。通过比较这两个平台的优势与挑战,开发者可以更好地决定哪个平台更适合他们的项目需求。
84 1
|
6天前
|
Java API Android开发
安卓应用程序开发的新手指南:从零开始构建你的第一个应用
【10月更文挑战第20天】在这个数字技术不断进步的时代,掌握移动应用开发技能无疑打开了一扇通往创新世界的大门。对于初学者来说,了解并学习如何从无到有构建一个安卓应用是至关重要的第一步。本文将为你提供一份详尽的入门指南,帮助你理解安卓开发的基础知识,并通过实际示例引导你完成第一个简单的应用项目。无论你是编程新手还是希望扩展你的技能集,这份指南都将是你宝贵的资源。
26 5