产品OR测试提出优化需求,输入的文字长度超过输入框,则超出的文本用…显示,当获取焦点的时候,显示全部内容,光标又要移动到最后。
思路:
1、第一想到的肯定是“ellipsize”属性设置为“end”,android:ellipsize=“end”。这个在文本框TextView有效,EditText未起作用,亲测。
2、设置固定宽度,或者看下固定文字,比如你设定的文本框只能显示十个中文字符就占满了,但如果输入了英文或者数字则长度又不好计算了,并且测试那还有N种手机屏幕在那等着来轮奸你呢,早点放弃为好!
3、得到输入文本框EditText的宽度,得到字符串的宽度,然后对比,字符串宽度>文本框宽度,就substring掉。这目前应该是最好的了方案了,并且Android提供了计算文本宽度的方法。
第一次尝试着写文章,排版逻辑什么的不怎么规范,还请多包涵!
开干:
建项目就略了。
1、布局文件:
activity_main.xml
Code Text:
<?
xml version=
"1.0"
encoding=
"utf-8"
?>
android
:layout_width=
"match_parent"
android
:layout_height=
"match_parent"
android
:background=
"#f2f2f2
”
android
:focusable=
"true"
android
:focusableInTouchMode=
"true"
tools
:context=
"com.threefei.rou.MainActivity"
>
<ScrollView
android
:layout_width=
"match_parent"
android
:layout_height=
"match_parent"
android
:fillViewport=
"true"
android
:scrollbarSize=
"0dp"
android
:scrollbars=
"none"
>
<LinearLayout
android
:layout_width=
"match_parent"
android
:layout_height=
"wrap_content"
android
:orientation=
"vertical"
>
<LinearLayout
android
:layout_width=
"match_parent"
android
:layout_height=
"50dp"
android
:background=
"@android:color/white"
android
:orientation=
"horizontal"
android
:paddingLeft=
"15dp"
android
:paddingRight=
"15dp"
>
<TextView
android
:layout_width=
"100dp"
android
:layout_height=
"match_parent"
android
:gravity=
"center_vertical"
android
:text=
"收件人地址:"
/>
<EditText
android
:id=
"@+id/et_address_1"
android
:layout_width=
"match_parent"
android
:layout_height=
"match_parent"
android
:background=
"@null"
android
:gravity=
"center_vertical"
android
:maxLength=
"30"
android
:maxLines=
"1"
android
:singleLine=
"true"
android
:textSize=
"12sp"
/>
</LinearLayout>
<View
android
:layout_width=
"match_parent"
android
:layout_height=
"0.5dp"
android
:background=
"@android:color/darker_gray"
/>
<LinearLayout
android
:layout_width=
"match_parent"
android
:layout_height=
"50dp"
android
:background=
"@android:color/white"
android
:orientation=
"horizontal"
android
:paddingLeft=
"15dp"
android
:paddingRight=
"15dp"
>
<TextView
android
:layout_width=
"100dp"
android
:layout_height=
"match_parent"
android
:gravity=
"center_vertical"
android
:text=
"发件人地址:"
/>
<EditText
android
:id=
"@+id/et_address_2"
android
:layout_width=
"match_parent"
android
:layout_height=
"match_parent"
android
:background=
"@null"
android
:gravity=
"center_vertical"
android
:maxLength=
"30"
android
:maxLines=
"1"
android
:singleLine=
"true"
android
:text=
""
android
:textSize=
"12sp"
/>
</LinearLayout>
<View
android
:layout_width=
"match_parent"
android
:layout_height=
"0.5dp"
android
:background=
"@android:color/darker_gray"
/>
<TextView
android
:id=
"@+id/tv_result"
android
:layout_width=
"match_parent"
android
:layout_height=
"wrap_content"
android
:layout_margin=
"20dp"
android
:background=
"@android:color/white"
android
:hint=
"提交结果值"
android
:padding=
"10dp"
android
:minHeight=
"150dp"
/>
<Button
android
:id=
"@+id/btn_click"
android
:layout_width=
"match_parent"
android
:layout_height=
"48dp"
android
:layout_margin=
"25dp"
android
:gravity=
"center"
android
:text=
"提交"
/>
</LinearLayout>
</ScrollView>
</LinearLayout>
Code Design:
2、Activity:
MainActivity.java
1)按产品的要求,那肯定得设置EditText的
setOnFocusChangeListener。
2)获得焦点的时候,得把原来超过长度范围值(原始值)设置到setText(String val),这个原始值,可以放到外面的成员变量里,也可以放到
EditText的tag里,这里的tag还没有其他用途,所以我把值放到tag里。
3)失去焦点的时候,得判断输入框的字符串是否大于控件的宽度,大于则截掉超出范围的字符串。
a.
EditText.setSelection(int index) 可以把光标定位到某个文字后面
b.
TextView.getPaint().measureText(String text) 可以得到字符串的宽度
c. 循环计算追加每个字符串的长度 > 文本框的长度
d. 最后substring
public class
MainActivity
extends
Activity
implements
View.OnClickListener
,
View.OnFocusChangeListener {
private static final int
CODE_MSG_ADDRESS_1
=
1
;
private static final int
CODE_MSG_ADDRESS_2
=
2
;
private
EditText
mEtAddress1
,
mEtAddress2
;
private
TextView
mTvResult
;
@Override
protected void
onCreate
(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState)
;
setContentView(R.layout.
activity_main
)
;
mEtAddress1
= (EditText) findViewById(R.id.
et_address_1
)
;
mEtAddress2
= (EditText) findViewById(R.id.
et_address_2
)
;
//提前先设置tag,避免在onFocuse里出现对象转换异常
mEtAddress1
.setTag(
""
)
;
mEtAddress2
.setTag(
""
)
;
mEtAddress1
.setOnFocusChangeListener(
this
)
;
mEtAddress2
.setOnFocusChangeListener(
this
)
;
mTvResult
= (TextView) findViewById(R.id.
tv_result
)
;
findViewById(R.id.
btn_click
).setOnClickListener(
this
)
;
}
@Override
public void
onWindowFocusChanged
(
boolean
hasFocus) {
super
.onWindowFocusChanged(hasFocus)
;
if
(hasFocus) {
//Activity的话,初始化赋值,可以在onWindowFocusChanged里设置,执行到这,控件的宽高可以得到了
//这个val可以从其他地方传过来
String val =
"幸福省幸福市幸福区幸福路幸福小区x栋xx号"
;
formartEditTextViewVal(
mEtAddress2
,
val)
;
}
}
@Override
public void
onClick
(View v) {
mEtAddress1
.clearFocus()
;
mEtAddress2
.clearFocus()
;
//真实的值放到了tag里了
String address1 =
mEtAddress1
.getTag().toString()
;
String address2 =
mEtAddress2
.getTag().toString()
;
StringBuilder sb =
new
StringBuilder(
"收件人地址:"
).append(address1)
;
sb.append(
"
\n
发件人地址:"
).append(address2)
;
mTvResult
.setText(sb.toString())
;
}
@Override
public void
onFocusChange
(View v
, boolean
hasFocus) {
switch
(v.getId()) {
if
(hasFocus) {
String text =
mEtAddress1
.getTag().toString().trim()
;
mEtAddress1
.setText(text)
;
mHandler
.sendEmptyMessage(
CODE_MSG_ADDRESS_1
)
;
//直接在这里设置光标移动到最后,这句代码无效,所以用到Handler跳出该方法,再设置光标
// UITools.setEditTextCursorEnd(mEtAddress1);
}
else
{
String text =
mEtAddress1
.getText().toString().trim()
;
formartEditTextViewVal(
mEtAddress1
,
text)
;
}
break;
if
(hasFocus) {
String text =
mEtAddress2
.getTag().toString().trim()
;
mEtAddress2
.setText(text)
;
mHandler
.sendEmptyMessage(
CODE_MSG_ADDRESS_2
)
;
}
else
{
String text =
mEtAddress2
.getText().toString().trim()
;
formartEditTextViewVal(
mEtAddress2
,
text)
;
}
break;
}
}
private
Handler
mHandler
=
new
Handler() {
@Override
public void
handleMessage
(Message msg) {
super
.handleMessage(msg)
;
if
(msg.
what
==
CODE_MSG_ADDRESS_1
) {
UITools.
setEditTextCursorEnd
(
mEtAddress1
)
;
}
else if
(msg.
what
==
CODE_MSG_ADDRESS_2
) {
UITools.
setEditTextCursorEnd
(
mEtAddress2
)
;
}
}
}
;
/**
* 格式化值
*
*
@param
editText
*
@param
text
*/
private void
formartEditTextViewVal
(EditText editText
,
String text) {
editText.setTag(text)
;
String str = UITools.
getEllipsisValue
(text
,
editText)
;
editText.setText(str)
;
}
}
补充下:使用Fragment初始化View获取控件宽高
/**
*
getViewTreeObserver的
vto.addOnGlobalLayoutListener<br/>
* 可以得到控件的宽高
*/
void
onGlobalLayout
() {
//向ViewTreeObserver 注册方法,以获取控件尺寸
ViewTreeObserver vto =
mEtAddress1
.getViewTreeObserver()
;
vto.addOnGlobalLayoutListener(
new
ViewTreeObserver.OnGlobalLayoutListener() {
public void
onGlobalLayout
() {
formartEditTextViewVal
(
mEtAddress1
,
"传递的值"
)
;
mEtAddress1
.getViewTreeObserver().removeGlobalOnLayoutListener(
this
)
;
}
})
;
}
3、工具类:
UITools.java
public class
UITools {
/**
* 将EditTextView的光标移动到最后
*
*
@param
editText
*/
public static void
setEditTextCursorEnd
(EditText editText) {
editText.setSelection(editText.getText().toString().length())
;
}
/**
* 获取字符串所占屏幕长度
*
*
@param
text
*
@param
textView
*
@return
*/
public static float
getTextValueWidth
(String text
,
TextView textView) {
if
(
null
== text ||
""
.equals(text)) {
return
0
;
}
TextPaint textPaint = textView.getPaint()
;
return
textPaint.measureText(text)
;
}
/**
* 计算字符串宽度超过文本框宽度的时候,显示带...的字符串
*
*
@param
text
*
@param
textView
*
@return
*/
public static
String
getEllipsisValue
(String text
,
TextView textView) {
String total =
""
;
float
textViewWdith = textView.getWidth()
;
// Log.e("xb", "-->文本框宽度:" + textViewWdith);
boolean
isCut =
false;
//循环计算追加后的字符串长度是否大于文本框长度
for
(
int
i =
1
;
i <= text.length()
;
i++) {
total = text.substring(
0
,
i)
;
float
totalWdith =
getTextValueWidth
(total
,
textView)
;
// Log.e("xb", "-->当前字符长度:" + totalWdith + ",字符串:" + total);
if
(totalWdith > textViewWdith) {
isCut =
true;
break;
}
}
//这里判断文本框长度是为了,有时候粗心,在view没有绘制好的时候,得到的宽度为0,不然substring就蹦了
if
(isCut && textViewWdith >
0
) {
//可以截取3,但"..."占大概2个中文字符宽度左右
return
total.substring(
0
,
total.length() -
2
) +
"..."
;
}
return
text
;
}
/**
* Toast提示
*
*
@param
context
*
@param
msg
*/
public static void
showToast
(Context context
,
String msg) {
Toast.
makeText
(context
,
msg
,
Toast.
LENGTH_SHORT
).show()
;
}
}
4、运行效果图
这里可以重写EditText,把逻辑放到重写类里去,使用就方便多了。
其实在项目中,文本框输入还有N种需求,
1、屏蔽特殊字符,或者屏蔽表情符号
2、只能输入中文或者英文
3、带一键删除按钮的EditTextView等
4、银行卡类型的格式化输入等要求
小bug提示:有的手机,貌似是moto手机,你设置了maxLength = 10,但测试在输入法中一次性敲打超过十个字的文本,可以跳过maxLength的设置,所以又得监听addTextChangedListener了。
案例下载地址:
http://download.csdn.net/download/liang_fei_xp/9968644