首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【Android】用户登录界面设计

【Android】用户登录界面设计

作者头像
三三是该溜子
发布2025-07-19 10:30:24
发布2025-07-19 10:30:24
3420
举报
文章被收录于专栏:该溜子的专栏该溜子的专栏

一:问题引入

我们现在要做的一件事情:当在登录界面的时候,点击“《用户协议》”的时候,能够进行页面跳转,而非勾选协议。

这里的思路其实也很好理解,我们把勾选框右侧的文本中的“《用户协议》”这几个字符进行特殊处理即可

二:代码展示

1:xml布局

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".CheckBoxActivity">

    <EditText
        android:id="@+id/et_user_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入用户名"
        android:inputType="text"
        android:maxLines="16" />

    <EditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入密码"
        android:inputType="textPassword"
        android:maxLength="16" />

    <CheckBox
        android:id="@+id/cb_agreement"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:checked="false"
        android:text="勾选,表示同意《用户协议》"
        android:textSize="16sp" />

    <Button
        android:id="@+id/btn_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登录" />
</LinearLayout>

2:java代码

代码语言:javascript
复制
		//拿到xml中定义的CheckBox
        CheckBox cbArgreement = findViewById(R.id.cb_agreement);

        /**
         * 处理富文本
         * 1:获取文本
         * 2:改成超链接
         * 3:设置点击后的监听事件,效果为页面跳转
         */
        String text = cbArgreement.getText().toString();//勾选表示同意《用户协议》
        SpannableString spannableString = new SpannableString(text);
        ClickableSpan clickableSpan = new ClickableSpan() {
            //设置一个点击事件监听事件
            @Override
            public void onClick(@NonNull View widget) {
                Toast.makeText(CheckBoxActivity.this,"假装显示了一个用户协议",Toast.LENGTH_SHORT).show();
            }
        };
        spannableString.setSpan(clickableSpan,7,13, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        cbArgreement.setText(spannableString);
        //允许文本控件显示一个可以点击的链接
        cbArgreement.setMovementMethod(LinkMovementMethod.getInstance());//这行代码才是精髓
        //但是也暴露出来了一个问题,点击《用户协议》这个超链接的时候会触发CheckBox的监听,这明显是不太合理的

上面这段代码非常折磨,我们慢慢一点一点分析,啃下来,加油

3:思路

①获取CheckBox中的文本

②设置一个监听事件

③Span把标记文本和监听器关联在一起

④设置一个超链接(提问,传入的是整个text文本,最后怎么会只有“《用户协议》”成了超链接,不明白)

⑤最后一行代码固定用法(也不太懂)

4:效果

在点击《用户协议》的时候会有弹窗:假装显示了一个用户协议

三:代码详细分析

1:CharSequence

译为字符序列

charSequence是一个接口,代表一段可以被读取的字符序列,常见的实现类

  • String:不可变的字符序列(一旦创建就不能修改)。
  • StringBuilder:可变的字符序列(可动态增删改,但只能修改字符内容,不能加样式)。
  • SpannableString带「标记」功能的可变字符序列(不仅能存字符,还能给指定范围的字符添加样式、点击事件等)。

span是SpannabledString的绝技,可以译为标记

2:SpannableString

代码语言:javascript
复制
// 1. 先拿到原始字符串(比如 CheckBox 上的文本 "勾选,表示同意《用户协议》" )
String string = cbAgreement.getText().toString();  

// 2. 用原始字符串创建 SpannableString 对象
SpannableString spannableString = new SpannableString(string);  
代码语言:javascript
复制
//1:Android当中专门处理富文本效果
SpannableString spannableString = new SpannableString(text);
(1)理解这个对象

创建SpannableString对象接收了一个String类型的静态文本;这一步其实就是把“普通的字符串”包装成一个“富文本容器”,这样后续就可以通过spannableString.setSpan(...)方法,对这个容器当中的某一段文字(通过 startend 索引指定范围 )添加各种特殊效果(比如点击事件、颜色 )。

(2)文字交互

Android 里的 TextViewCheckBox 等控件,虽然能显示普通文本,但如果想让部分文字有特殊样式或交互(比如 “用户协议” 可点击 ),直接用 String 做不到。 SpannableString 就是专门用来解决这个问题的:先把普通字符串包装成 SpannableString ,再给局部加效果,最后设置回控件显示,就能实现 “富文本” 效果。

四:事件监听

类比:按钮监听和CheckBox监听

代码语言:javascript
复制
//按钮
 		Button loginButton = findViewById(R.id.btn_login);
        loginButton.setOnClickListener(new View.OnClickListener() {setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //这里按钮的监听器的相关代码
            }
        });
//CheckBox复选框
		CheckBox cbArgreement = findViewById(R.id.cb_agreement);
        cbArgreement.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                
            }
        });
代码语言:javascript
复制
 ClickableSpan clickableSpan = new ClickableSpan() {
            //设置一个点击事件监听事件
            @Override
            public void onClick(@NonNull View widget) {
                Toast.makeText(CheckBoxActivity.this,"假装显示了一个用户协议",Toast.LENGTH_SHORT).show();
            }
        };

设置弹窗并显示

五:.setSpan()

代码语言:javascript
复制
spannableString.setSpan(clickableSpan,7,13, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

1:参数分析

(1)标记对象

what 被标记的标记(这里就是clickableSpan)

(2)初始区间

起始下标和结束下标 左闭右开区间 [start,end) 初始范围的规则 跟最后一个参数flags的区间没有关系

exclusive 包含 inclusive 不包含

(3)文本编辑后的区间范围

Spanned.SPAN_EXCLUSIVE_EXCLUSIVE(最常用)区间为:左开右开

举例说明:

假设你给 《用户协议》 设了 SPAN_EXCLUSIVE_EXCLUSIVE,然后在 《 前面插入一个 “淦”,那么新插入的 “淦”不会被算作 Span 的一部分,只有原来的 《用户协议》 仍保持 Span 效果。

注:原来的 索引从 7 变成了 8,但 《用户协议》 本身的 Span 范围会自动调整为 8 ≤ 索引 < 14(跟着字符移动),依然保持标记。

我们一般也希望,编辑后的文本不要影响到之前的span标记,flags参数采用的多为左开右开区间。(实操效果很难展示出来,略)

  • Spanned.SPAN_EXCLUSIVE_EXCLUSIVE:前后都不包括
  • Spanned.SPAN_EXCLUSIVE_INCLUSIVE:前面不包括,后面包括
  • Spanned.SPAN_INCLUSIVE_EXCLUSIVE:前面包括,后面不包括
  • Spanned.SPAN_INCLUSIVE_INCLUSIVE:前后都包括

六:超链接响应

代码语言:javascript
复制
		cbArgreement.setText(spannableString);
        //允许文本控件显示一个可以点击的链接
        cbArgreement.setMovementMethod(LinkMovementMethod.getInstance());//这行代码才是精髓

1:代码分析

(1)让设置生效

我们设置好了spannableString(包括文本样式,事件标记,监听事件),现在需要把它通过setText()设置给CheckBox(TextView父类),TextView就会根据设置进行渲染。

(2)超链接响应点击事件

setMovementMethod() 为CheckBox设置文本移动方法,使超链接能够响应文本监听器

LinkMovementMethod.getInstance() 获取实例,返回一个单例对象

2:原理总结

  • LinkMovementMethod是一个内置的文本移动方法,专门用来处理超链接
  • 它会拦截TextView的触摸事件,识别出span区域,并触发onClick方法
  • 如果不设置这个方法,虽然文本会显示为超链接样式(如下划线、蓝色),但点击时不会触发任何事件,而是将点击事件传递给 CheckBox 本身(导致勾选状态变化)。

七:分开勾选和用户协议跳转功能

1:问题引入

点击用户协议,勾选功能也被调用了。说明两个事件被同一个监听器监听了,我们要把他俩给分开,思路把xml中TextView和CheckBox给分开装饰,再在Java中分别处理监听逻辑

2:xml代码修改

主要是把CheckBox和TextView放到一个LinearLayout线性布局下

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".CheckBoxActivity">

    <EditText
        android:id="@+id/et_user_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入用户名"
        android:inputType="text"
        android:maxLines="16" />

    <EditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入密码"
        android:inputType="textPassword"
        android:maxLength="16" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <CheckBox
            android:id="@+id/cb_box"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:checked="false"
            android:text="勾选,表示同意"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/tv_agreement"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="《用户协议》"
            android:textSize="16sp" />
        
    </LinearLayout>


    <Button
        android:id="@+id/btn_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登录" />


</LinearLayout>

3:Java代码

注意第十七行代码;太恶心了,猜测原因:start和end的设置越界,所以导致空指针异常,进而跳转不到登录的页面(一点击按钮就闪退),一个块一个块排查出来的。

代码语言:javascript
复制
spannableString.setSpan(clickableSpan,0,text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
代码语言:javascript
复制
        /**
         * 处理富文本
         * 1:获取文本
         * 2:改成超链接
         * 3:设置点击后的监听事件,效果为页面跳转
         */
        TextView tv_agreement = findViewById(R.id.tv_agreement);
        String text = tv_agreement.getText().toString();//《用户协议》
        SpannableString spannableString = new SpannableString(text);
        ClickableSpan clickableSpan = new ClickableSpan() {
            //设置一个点击事件监听事件
            @Override
            public void onClick(@NonNull View widget) {
                Toast.makeText(CheckBoxActivity.this,"假装显示了一个用户协议",Toast.LENGTH_SHORT).show();
            }
        };
        spannableString.setSpan(clickableSpan,0,text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        tv_agreement.setText(spannableString);
        //允许文本控件显示一个可以点击的链接
        tv_agreement.setMovementMethod(LinkMovementMethod.getInstance());//这行代码才是精髓
        //但是也暴露出来了一个问题,点击《用户协议》这个超链接的时候会触发CheckBox的监听,这明显是不太合理的



        /**
         * 实时监听勾选状态
         */
        CheckBox cb_box = findViewById(R.id.cb_box);
        cb_box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){

            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                //方式三
                if(isChecked){
                    Toast.makeText(CheckBoxActivity.this,"感谢您勾选协议",Toast.LENGTH_SHORT).show();
                }else{
                    Toast.makeText(CheckBoxActivity.this,"请勾选协议",Toast.LENGTH_SHORT).show();
                }
            }
        });
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-07-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一:问题引入
  • 二:代码展示
    • 1:xml布局
    • 2:java代码
    • 3:思路
    • 4:效果
  • 三:代码详细分析
    • 1:CharSequence
    • 2:SpannableString
      • (1)理解这个对象
      • (2)文字交互
    • 四:事件监听
  • 五:.setSpan()
    • 1:参数分析
      • (1)标记对象
      • (2)初始区间
      • (3)文本编辑后的区间范围
  • 六:超链接响应
    • 1:代码分析
      • (1)让设置生效
      • (2)超链接响应点击事件
    • 2:原理总结
  • 七:分开勾选和用户协议跳转功能
    • 1:问题引入
    • 2:xml代码修改
    • 3:Java代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档