我有一些用于手机号码输入的 EditText。应用程序必须为每个国家/地区添加唯一的文本。例如对于亚美尼亚,必须添加+374
,用户必须填写其他数字。也+374
必须是不可更改的,用户不能更改或删除它。那么有一些方法可以做到这一点吗?
编辑:
我不想在此文本中使用 textView 或其他视图并将其放在 ediText 的左侧。我想找到一些操作较少的方法。我需要冻结文本而不是检查每个文本更改或在用户删除其中的某些部分时添加丢失的文本。
我有一些用于手机号码输入的 EditText。应用程序必须为每个国家/地区添加唯一的文本。例如对于亚美尼亚,必须添加+374
,用户必须填写其他数字。也+374
必须是不可更改的,用户不能更改或删除它。那么有一些方法可以做到这一点吗?
编辑:
我不想在此文本中使用 textView 或其他视图并将其放在 ediText 的左侧。我想找到一些操作较少的方法。我需要冻结文本而不是检查每个文本更改或在用户删除其中的某些部分时添加丢失的文本。
创建一个自定义可绘制类,这将有助于将文本转换为可绘制对象。
public class TextDrawable extends Drawable {
private final String text;
private final Paint paint;
public TextDrawable(String text) {
this.text = text;
this.paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(16f);
paint.setAntiAlias(true);
paint.setTextAlign(Paint.Align.LEFT);
}
@Override
public void draw(Canvas canvas) {
canvas.drawText(text, 0, 6, paint);
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
然后将drawable设置为edittext的左侧
EditText et = (EditText)findViewById(R.id.editText1);
String code = "+374";
et.setCompoundDrawablesWithIntrinsicBounds(new TextDrawable(code), null, null, null);
et.setCompoundDrawablePadding(code.length()*10);
其中edittext在布局文件中定义为
<EditText
android:id="@+id/editText1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:ems="10" >
<requestFocus />
</EditText>
最终输出看起来像
public class MainActivity extends Activity {
private EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = (EditText) findViewById(R.id.editText1);
editText.setText("+374");
Selection.setSelection(editText.getText(), editText.getText().length());
editText.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
// TODO Auto-generated method stub
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
if (!s.toString().startsWith("+374")) {
editText.setText("+374");
Selection.setSelection(editText.getText(), editText
.getText().length());
}
}
});
}
}
您可以创建类扩展 AppCompatEditText 或 EditText。
public class CEditTextMaster extends AppCompatEditText {
private boolean isNeedNoChangeSomeCharacters;
private String charactersNoChange;
public CEditTextMaster(Context context) {
super(context);
init(context, null);
}
public CEditTextMaster(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public CEditTextMaster(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
public void init(Context context, @Nullable AttributeSet attrs) {
if (isInEditMode())
return;
addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (isNeedNoChangeSomeCharacters && charactersNoChange != null) {
if (!getText().toString().startsWith(charactersNoChange)) {
removeTextChangedListener(this);
if (charactersNoChange.length() > s.length()) {
setText(charactersNoChange);
} else {
setText(charactersNoChange + getText());
}
setSelection(getText().toString().length());
addTextChangedListener(this);
}
}
}
});
}
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
if (isNeedNoChangeSomeCharacters && charactersNoChange != null) {
if (length() > charactersNoChange.length() && selStart < charactersNoChange.length()) {
setSelection(charactersNoChange.length(),selEnd);
}
}
}
@Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
if (isNeedNoChangeSomeCharacters && charactersNoChange != null) {
if (!getText().toString().trim().startsWith(charactersNoChange)) {
setText(charactersNoChange + getText());
}
}
}
public void setCharactersNoChangeInitial(String charactersNoChange) {
isNeedNoChangeSomeCharacters = true;
this.charactersNoChange = charactersNoChange;
if (!getText().toString().trim().startsWith(charactersNoChange)) {
setText(getText());
}
}
}
用来:
edt.setCharactersNoChangeInitial("+734 ");
使用文本观察器,当用户输入 +3 时,它以 +374 完成,它比较前四个字符,如果相同,则禁用软键盘的后按,这样它就不会更改文本并输入附加的另一个数字从 textwatcher 使用的文本
我选择了一个类似于另一个提交的解决方案,扩展EditText
和修改onSelectionChanged
. 这甚至可以防止用户进入该区域。
这是我正在使用的:
import android.content.Context
import android.text.Editable
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatEditText
class PrefixEditText(context: Context, attrs: AttributeSet?) : AppCompatEditText(context, attrs) {
private var prefix: String? = null
fun setPrefix(prefix: String) {
this.prefix = prefix
setText(prefix)
addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
override fun afterTextChanged(s: Editable?) {
// Block deleting the prefix
if (s?.startsWith(prefix) == false) {
setText(prefix)
}
}
})
}
override fun onSelectionChanged(selStart: Int, selEnd: Int) {
var newStart = selStart
var newEnd = selEnd
prefix?.length?.let {
newStart = if (selStart < it) it else selStart
newEnd = if (selEnd < it) it else selEnd
}
if (selStart != newStart || selEnd != newEnd) {
setSelection(newStart, newEnd)
} else {
super.onSelectionChanged(selStart, selEnd)
}
}
// Here to conform to EditText's API
// Could also just override getText()
fun getPostText(): Editable? {
return prefix?.let {
Editable.Factory.getInstance().newEditable(text)?.delete(0, it.length)
} ?: run {
text
}
}
// Here for convenience, to avoid instantiating a new Editable, if the text is all you need
fun getPostCharSeq(): CharSequence? {
return prefix?.let {
text?.substring(it.length)
} ?: run {
text
}
}
}
通过测试:
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.ActivityTestRule
import com.roosterteeth.roosterteeth.TestActivity
import org.junit.Assert
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class PrefixEditTextTest {
@Rule
@JvmField
var activityRule: ActivityTestRule<TestActivity> = ActivityTestRule(TestActivity::class.java, true, true)
private fun setupView(prefix: String, message: String): PrefixEditText {
val editText = PrefixEditText(activityRule.activity, null)
val lp = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
activityRule.activity.addContentView(editText, lp)
editText.setPrefix(prefix)
editText.append(message)
return editText
}
@Test
fun testSelection() {
activityRule.runOnUiThread {
val prefix = "pre: "
val message = "hello world"
val editText = setupView(prefix, message)
editText.setSelection(0)
Assert.assertEquals(editText.selectionStart, prefix.length)
Assert.assertEquals(editText.selectionEnd, prefix.length)
editText.setSelection(0, editText.length())
Assert.assertEquals(editText.selectionStart, prefix.length)
Assert.assertEquals(editText.selectionEnd, editText.length())
}
}
@Test
fun testGetPostText() {
activityRule.runOnUiThread {
val prefix = "pre: "
val message = "hello world"
val editText = setupView(prefix, message)
Assert.assertEquals(message, editText.getPostText().toString())
// This test is after to make sure that getting the post text did not actually modify the contents
Assert.assertEquals("pre: $message", editText.text.toString())
}
}
@Test
fun testGetPostCharSeq() {
activityRule.runOnUiThread {
val prefix = "pre: "
val message = "hello world"
val editText = setupView(prefix, message)
Assert.assertEquals(message, editText.getPostCharSeq())
// This test is after to make sure that getting the post text did not actually modify the contents
Assert.assertEquals("pre: $message", editText.text.toString())
}
}
}