文本

qiang.zhang大约 16 分钟

文本

屏幕显示像素单位

Android支持的像素单位有:px(像素)、in(英寸)、mm(毫米)、pt(磅,1/72英寸)、dp(与设备无关的显示单位)、dip(就是dp)、sp(用于设置字体大小)。 其中,常用的有px、dp和sp三种。

具体来说,px是手机屏幕上可显示的最小单位,与物理设备的显示屏有关。一般来说,同样尺寸的屏幕(比如5寸的手机)看起来越清晰,像素的密度越高,以px计量的分辨率也越大。

dp与物理设备无关,只与屏幕的尺寸有关。一般来说,同样尺寸的屏幕以dp计量的分辨率是一样的,无论这个手机是哪个厂家生产的,dp大小都一样。

sp的原理跟dp差不多,专门用于设置字体大小。手机在系统设置里可以调整字体的大小(小、普通、大、超大)。设置普通字体时,同数值dp和sp的文字看起来一样大;如果设置为大字体,用dp设置的文字没有变化,用sp设置的文字就变大了。例如,当系统设置普通字体时,18dp与18sp的文字一样大;当系统设置大字体时,18dp的文字大小不变,18sp的文字却增大了。

即是dp与系统设置的字体大小没有关系,而sp会随系统设置的字体大小变大或变小。

dp与px的转换

dp和px之间的联系取决于具体设备上的像素密度,像素密度就是DisplayMetrics里的density参数。当density=1.0时,表示一个dp值对应一个px值;当density=1.5时,表示两个dp值对应3个px值;当density=2.0时,表示一个dp值对应两个px值。

转换代码如下:

    // 根据手机的分辨率从dp的单位转换成px像素
    public static int dp2px(Context context,float dpValue){
        // 获取当前手机的像素密度
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int)(dpValue*scale+0.5f);// 四舍五入取整
    }
    
    //根据手机的分辨率从px像素单位转换成dp单位
    public static int px2dp(Context context,float pxValue){
        // 获取当前手机的像素密度
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int)(pxValue/scale+0.5f);// 四舍五入取整
    }

值得注意的是:在XML布局文件中,为了让不同设备屏幕拥有统一的显示效果,除了sp用于设置文字大小外,其余要用尺寸大小的地方都用dp。在代码中情况又有所不同,Android用于设置大小的函数都以px为单位。无论是LayoutParams里的width和height,还是setMargins和setPadding,参数单位都是px,要想在代码中使用dp设置布局大小或间距,得先把dp值转换成px值。

屏幕颜色

在Android中,颜色值由透明度alpha和RGB(红、绿、蓝)三原色定义,有八位十六进制数与六位十六进制数两种编码,例如八位编码FFEEDDCC,FF表示透明度,EE表示红色的浓度,DD表示绿色的浓度,CC表示蓝色的浓度。透明度为FF表示完全不透明,为00表示完全透明。RGB三色的数值越大颜色越浓也就越亮,数值越小颜色越暗。

小技巧:亮到极致就是白色,暗到极致就是黑色

六位十六进制编码有两种情况,在XML文件中默认不透明(透明度为FF),在代码中默认透明(透明度为00)

屏幕分辨率

在App编码中时常要取手机的屏幕分辨率(如当前屏幕的宽和高),然后动态调整界面上的布局。在代码中获取分辨率就是想办法获得DisplayMetrics对象,然后从该对象中获得宽度、高度、像素密度等信息。

下面是DisplayMetrics类的常用属性说明:

  • widthPixels:以px为单位计量的宽度值。
  • heightPixels:以px为单位计量的高度值。
  • density:像素密度,即一个dp单位包含多少个px单位。

取当前屏幕的宽度、高度、像素密度的代码示例:

    public static int getScreenWidth(Context context){
        // 从系统服务中获取窗口管理器
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        // 从默认显示器中获取显示参数保存到dm对象中
        wm.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.widthPixels;
    }

    public static int getScreenHeight(Context context){
        // 从系统服务中获取窗口管理器
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        // 从默认显示器中获取显示参数保存到dm对象中
        wm.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.heightPixels;
    }
    
    public static float getScreenDensity(Context context){
        // 从系统服务中获取窗口管理器
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        // 从默认显示器中获取显示参数保存到dm对象中
        wm.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.density;
    }

视图View的基本属性

view

View是Android的基本视图,所有控件和布局都是由View类直接或间接派生而来的。故而View类的基本属性和方法是各控件和布局通用的。

这是XML中的属性值定义:

id:指定该视图的编号。
layout_width:指定该视图的宽度。可以是具体的dp数值;可以是match_parent,表示与上级视图一样宽;也可以是wrap_content,表示与内部内容一样宽(内部内容若超过上级视图的宽度,则该视图保持与上级视图一样宽,超出宽度的内容得进行滚动才能显示出来)。
layout_height:指定该视图的高度。取值说明同layout_width。
layout_margin:指定该视图与周围视图之间的空白距离(包括上、下、左、右)。另有layout_marginTop、layout_marginBottom、layout_marginLeft、layout_marginRight分别表示单独指定视图与上边、下边、左边、右边视图的距离。
minWidth:指定该视图的最小宽度。
minHeight:指定该视图的最小高度。
background:指定该视图的背景。背景可以是颜色,也可以是图片。
layout_gravity:指定该视图与上级视图的对齐方式。对齐方式的取值说明可以参考下面的表格,若同时适用多种对齐方式,则可使用竖线“|”把多种对齐方式拼接起来。
padding:指定该视图边缘与内部内容之间的空白距离。另有paddingTop、paddingBottom、paddingLeft、paddingRight分别表示指定视图边缘与内容上边、下边、左边、右边的距离。
visibility:指定该视图的可视类型。

当然也可以通过代码设定:


setLayoutParams:设置该视图的布局参数。参数对象的构造函数可以设置视图的宽度和高度。其中,LayoutParams.MATCH_PARENT表示与上级视图一样宽,也可以是LayoutParams.WRAP_CONTENT,表示与内部内容一样宽;参数对象的setMargins方法可以设置该视图与周围视图之间的空白距离。

setMinimu mWidth:设置该视图的最小宽度。
setMinimumHeight:设置该视图的最小高度。
setBackgroundColor:设置该视图的背景颜色。
setBackgroundDrawable:设置该视图的背景图片。
setBackgroundResource:设置该视图的背景资源id。
setPadding:设置该视图边缘与内部内容之间的空白距离。
setVisibility:设置该视图的可视类型。

XML中的对齐方式Gravity类中的对齐方式说明
leftLEFT靠左对齐
rightRIGHT靠右对齐
topTOP向上对齐
bottomBOTTOM向下对齐
centerCENTER居中对齐
center_horizontalCENTER_HORIZONTAL水平方向居中
center_verticalCENTER_VERTICAL垂直方向居中
----------
XML中可视的类型Gravity类中的可视类型说明
visibleVISIBLE可见,默认值
invisibleINVISIBLE不可见,虽然看不见但还是会占据位置
goneGONE消失,看不见也不会占据位置
  • margin是指当前视图与周围视图的距离,padding是指当前视图与内部内容的距离

ViewGroup

视图组ViewGroup是一类特殊视图,所有的布局类视图都是从它派生而来的。Android中的视图分为两类,一类是布局,另一类是控件。布局与控件的区别在于:布局本质上是个容器,里面还可以放其他视图(包括子布局和子控件);控件是一个单一的实体,已经是最后一级,下面不能再挂其他视图。

ViewGroup有3个方法,这3个方法也是所有布局类视图共同拥有的:

addView:往布局中添加一个视图。
removeView:从布局中删除指定视图。
removeAllViews:删除该布局下的所有视图。

TextView

TextView是最基础的文本显示控件

XML中的属性TextView类的设置方法说明
textsetText设置文本内容
textColorsetTextColor设置文本颜色
textSizesetTextSize设置文本大小
textAppearancesetTextAppearance设置文本风格,风格定义在res/styles.xml
gravitysetGravity设置文本的对齐方式
linssetLines指定文本行数
maxLinessetMaxLines指定文本的最大行数

跑马灯&文字滚动效果

实现这个效果需要定义一些其他的属性值,如下:

XML中的属性TextView类的设置方法说明
singlelinesetSingleLine指定文本是否单行显示
ellipsizesetEllipsize指定文本超出范围后的省略方式
focusablesetFocusable指定是否获得焦点,跑马灯效果需要设置为true
focusableintouchmodesetFocusableInTouchMode指定在触摸时是否获得焦点,跑马灯效果需要设置为true
setMovementMethod设置文本移动的方式,可以设置为ScrollingMovementMethod,如果不设置将无法拉动文本
scrollbars指定滚动条的方向,取值vertical,如果不指定将不显示滚动条
---
XML中的省略方式TruncateAt类中省略方式说明
startSTART省略号在前面
middleMIDDLE省略号在中间
endEND省略号在末尾
marqueeMARQUEE跑马灯显示
  • tip: 视频弹幕、直播弹幕效果实现,将背景设置为透明,字体颜色设置为白色或其他颜色,开启跑马灯效果,让文字从左到右滚动,半屏或全屏可以通过改变View的高度,或者最大显示的行数控制.

EditText

EditText是文本编辑框,用户可在此输入文本等信息。EditText的常用属性说明如下。

inputType:指定输入的文本类型,代码中对应的方法是setInputType。输入类型的取值说明可以见下表,若同时使用多种文本类型,则可使用竖线“|”把多种文本类型拼接起来。
maxLength:指定文本允许输入的最大长度。该属性无法通过代码设置。
hint:指定提示文本的内容,代码中对应的方法是setHint。
textColorHint:指定提示文本的颜色,代码中对应的方法是setHintTextColor。
输入类型说明
text文本
textPassword文本密码,显示时用 * 符号代替
number整型数
numberSigned带符号的数字,允许在开头带负号
numberDecimal带小数点的数字
numberPassword数字密码,显示时用 * 符号代替
datetime时间日期格式,除了数字以外,还允许输入横线、斜杠、空格、冒号
date日期格式,除了数字外,还允许输入横线 - 和斜杠 /
time时间格式,除了数字外,还允许输入冒号 :

除了上述文本与提示文本的基本操作外,实际开发中还常常关注4个方面:更换编辑框的光标、更换编辑框的边框、自动隐藏输入法、输入回车符自动跳转。

更换编辑框的光标

EditText与光标处理有关的属性主要有两个,分别是:cursorVisible,指定光标是否可见。代码中对应的方法是setCursorVisible。textCursorDrawable,指定光标的图像。该属性无法通过代码设置。如果要隐藏光标,就要把cursorVisible设置为false。如果要变更光标的样式,就要修改textCursorDrawable设置新图像。如图3-13所示,光标被换成自定义的红色竖线光标。

更换编辑框的边框

EditText的边框通过background属性控制,如果要隐藏边框,就要把background设置为@null;如果要修改边框的样式,就要将background设置为其他边框图形。

自动隐藏输入法

如果页面上有EditText控件,开发者又没做其他处理,那么用户打开该页面时往往会自动弹出输入法。这是因为编辑框会默认获得焦点,即默认模拟用户的点击操作,于是输入法的软键盘就弹出了。要想避免这种情况,就得阻止编辑框默认获得焦点。比较常见的做法是给该页面的根节点设置focusable和focusableInTouchMode属性,通过将这两个属性设置为true可强制让根节点获得焦点,从而避免输入法自动弹出的尴尬。由于软键盘通常会遮盖“登录”“确认”“下一步”等按钮,造成用户输入完毕得再点一次返回键才能关闭软键盘。大家都希望省事点,比如手机号输入满11位软键盘自动关闭,这样就会极大改善用户体验。

一个好用的App就是在这一点一滴中体现出来的。

想让编辑框文本达到指定长度时自动关闭输入法,开发者需要获得两个参数,第一个是该编辑框允许输入的最大长度,第二个是当前已经输入的文本长度。当已输入的文本长度等于最大长度时,即可触发关闭软键盘。自动隐藏输入法可分解为3个功能点,分别是获取编辑框的最大长度、监控当前已输入的文本长度和关闭软键盘。

(1)获取编辑框的最大长度前面提到maxLength属性可设置最大长度,但是EditText并没有直接提供获取最大长度的方法,不过开发者可以通过反射方式间接获得最大长度,具体代码参见本书附带源码middle模块里面ViewUtil.java的getMaxLength方法。

(2)监控当前已输入的文本长度这个监控操作用到一个文本监听器接口TextWatcher,该接口提供了3个监控方法,具体说明如下。

beforeTextChanged:在文本改变之前触发。
onTextChanged:在文本改变过程中触发。
afterTextChanged:在文本改变之后触发。这里用到的是afterTextChanged方法,需要自己写个监听器实现TextWatcher接口,另外再给EditText对象调用addTextChangedListener方法注册该监听器。

(3)关闭软键盘输入法通过系统服务INPUT_METHOD_SERVICE管理,所以隐藏输入法也要通过该服务实现。下面是关闭软键盘的两种方式及其代码:

    public static void hideAllInputMethod(Activity activity) {
        // 从系统服务中获取输入法管理器
        InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputMethodManager.isActive()) {
            // 软键盘如果打开则关闭
            inputMethodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

    public static void hideOneInputMethod(Activity activity, View view){
        // 从系统服务中获取输入法管理器
        InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
        // 关闭屏幕上的输入法软键盘
        inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(),0);
    }

示例:

private class HideTextWatcher implements TextWatcher {
        private EditText mView; // 声明一个编辑框对象
        private int mMaxLength; // 声明一个最大长度变量

        public HideTextWatcher(EditText v, int maxLength) {
            super();
            mView = v;
            mMaxLength = maxLength;
        }

        // 在编辑框的输入文本变化前触发
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

        // 在编辑框的输入文本变化时触发
        public void onTextChanged(CharSequence s, int start, int before, int count) {}

        // 在编辑框的输入文本变化后触发
        public void afterTextChanged(Editable s) {
            String str = s.toString(); // 获得已输入的文本字符串
            // 输入文本达到11位(如手机号码),或者达到6位(如登录密码)时关闭输入法
            if ((str.length() == 11 && mMaxLength == 11)
                || (str.length() == 6 && mMaxLength == 6)) {
                ViewUtil.hideOneInputMethod(EditHideActivity.this, mView); // 隐藏输入法软键盘
            }
        }
    }

输入回车符自动跳转

在录入用户信息时(比如输入姓名、密码等),往EditText控件输入回车键,常常不是换行而是让光标直接跳到下一个编辑框。 该功能也用到了文本监听器接口TextWatcher,主要监听用户是否输入回车符,如果监控到已输入回车符,就自动将焦点移到下一个控件,从而实现回车符自动跳转的要求。

下面是一个回车符监听器的代码例子,注意注释部分的文字说明:


public final class JumpTextWatcher implements TextWatcher {

    private final EditText thisView;

    private final View nextView;

    public JumpTextWatcher(EditText thisView, View nextView) {
        this.thisView = thisView;
        this.nextView = nextView;
    }

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

    @Override
    public void afterTextChanged(Editable editable) {
        String s = editable.toString();
        // 判断是否是回车符或者换行符
        if(s.contains("\r")||s.contains("\n")){
            //去掉回车符和换行符
            thisView.setText(s.replace("\r","").replace("\n",""));

            if(nextView!=null){
                nextView.requestFocus();
                if(nextView instanceof EditText){
                    Editable editable1 = ((EditText) nextView).getText();
                    Selection.setSelection(editable1,editable1.length());
                    //((EditText) nextView).setSelection(editable1.length());
                }
            }
        }
    }
}

自动完成编辑框AutoCompleteTextView

自动完成编辑框一般用于搜索文本框,如在电商App的搜索框输入商品文字时,下方会自动弹出提示词列表,方便用户快速选择具体商品。

AutoCompleteTextView的实现原理是:EditText结合监听器TextWatcher与下拉列表Spinner,一旦监控到EditText的文本发生变化,就自动弹出适配好的文字下拉列表,选中具体的下拉项向EditText填入相应文字。

xml属性值代码设置说明
completionHintsetCompletionHint设置下拉列表底部的提示文字
completionThresholdsetThreshold设置至少输入多少个字符才会显示
dropDownHorizontalOffsetsetDropDownHorizontalOffset设置下拉列表与文本框之间的水平偏移
dropDownVerticalOffsetsetDropDownVerticalOffset设置下拉列表与文本框之间的垂直偏移
dropDownHeightsetDropDownHeight设置下拉列表的高度
dropDownWidthsetDropDownWidth设置下拉列表的宽度
setAdapter设置数据适配器
 String [] hintArray = {"第一个","第二个"};
 AutoCompleteTextView completeTextView = new AutoCompleteTextView(this);
 completeTextView.setAdapter(new ArrayAdapter<String>(this,R.layout.布局文件,hintArray));

Button

Button派生自TextView,二者在UI上的区别主要是Button控件有个按钮外观,提示用户点击这里。 系统默认的按钮外观通常都不好看,需要更换靓一点、活泼一点的图片,这时在布局文件中修改Button节点的background属性就可以了。

如果把background属性设置为@null,就会去除Button控件的背景样式,此时的Button看起来跟TextView没什么区别。

因为点击和长按监听器都来源于View类,所以这两个方法及其监听器并非Button特有的,而是所有布局和控件都能使用的,一般用于为按钮控件注册点击和长按事件。Android中的简单按钮主要是Button和ImageButton。这两个按钮对点击和长按监听器的使用方法并不复杂,主要步骤如下:

步骤01

自己定义一个扩展自监听器的类,如点击监听器扩展自View.OnClickListener,长按监听器扩展自View.OnLongClickListener。为了方便起见,也可以直接给页面的Activity类加上监听器接口。

步骤02

在自定义监听器类中重写点击或者长按方法,加入事件处理的代码。点击方法的名称是onClick,长按方法的名称是onLongClick。

步骤03

哪个视图要响应点击或长按,就给哪个视图注册对应的监听器对象。点击事件的注册方法是setOnClickListener,长按事件的注册方法是setOnLongClickListener。

示例:

button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    
                }
            });

 button.setOnLongClickListener(new View.OnLongClickListener() {
     @Override
     public boolean onLongClick(View v) {
         return false;
     }
 });

Loading...