English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Введение
Хорошее приложение требует интерфейса входа с хорошим пользовательским опытом, в настоящее время, интерфейсы входа во многих приложениях имеют функцию一键删除 имени пользователя и пароля,提示 имя пользователя и пароль не введены, а также функцию ввода кода проверки.
примечание: так как лень было вырезать изображение, иконка программы выглядит не очень.
Схематическое изображение во время выполнения программы:
Сначала файл разметки не представляет сложности.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <ImageView android:id="@+id/tv_login" android:src="@drawable/ic_launcher" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:gravity=\ /> <com.example.administrator.texttest.DeletableEditText> android:id="@+id/tv_user" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="30dp" android:layout_below="@id/tv_login" android:drawableLeft=\ android:drawableRight=\ android:hint="введите аккаунт" android:ems=\ <com.example.administrator.texttest.DeletableEditText> android:id=\ android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="30dp" android:layout_below=\ android:drawableLeft=\ android:drawableRight=\ android:hint=\ android:inputType=\ android:ems=\ <LinearLayout android:id=\ android:orientation=\ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below=\ <LinearLayout android:id=\ android:orientation=\ android:layout_width="wrap_content" android:layout_height=\ <TextView> android:id=\ android:layout_width=\ android:layout_height=\ android:visibility=\ android:gravity=\ android:textSize="30dp" /> <TextView> android:id=\ android:layout_width=\ android:layout_height=\ android:visibility=\ android:gravity=\ android:textSize="30dp" /> <TextView> android:id=\ android:layout_width=\ android:layout_height=\ android:visibility=\ android:gravity=\ android:textSize="30dp" /> <TextView> android:id=\ android:layout_width=\ android:layout_height=\ android:visibility=\ android:gravity=\ android:textSize="30dp" /> </LinearLayout> <LinearLayout android:id=\ android:orientation=\ android:layout_width="wrap_content" android:layout_height=\ <ImageView android:layout_height=\ android:layout_width=\ android:id=\ <ImageView android:layout_height=\ android:layout_width=\ android:id=\ <ImageView android:layout_height=\ android:layout_width=\ android:id=\ <ImageView android:layout_height=\ android:layout_width=\ android:id=\ </LinearLayout> <LinearLayout android:orientation=\ android:layout_height="wrap_content" android:layout_width=\ <EditText android:layout_height="wrap_content" android:layout_width=\ android:textSize="30dp" android:id=\ android:maxLength=\ android:singleLine=\ android:hint=\ <TextView> android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="Результат" android:id="@+id/tvCheck" android:textSize="30dp" android:visibility="gone"/> </LinearLayout> </LinearLayout> <Button android:id="@+id/bt_login" android:text="ВХОД" android:textSize="30dp" android:layout_below="@id/lyYanzhengma" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout>
Затем загружаются некоторые файлы макетов и инициализируются некоторые控件
//Кнопка входа private Button btLogin; //Учётная запись private DeletableEditText userEditText; //Пароль private DeletableEditText psdEditText; //Текст чисел кода проверки private TextView tvHideA,tvHideB,tvHideC,tvHideD; //Текст изображения кода проверки private ImageView ivNumA,ivNumB,ivNumC,ivNumD; //Текст для ввода кода проверки private EditText etCheck; //Текст для отображения проверки кода private TextView tvCheck; //Хранение чисел каждого кода проверки private String numStrTmp = ""; //Хранение всего кода проверки private String numStr = ""; //Массив для хранения кода проверки private int[] numArray = new int[4]; // хранящая цвета массива private int[] colorArray = new int[6]; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setupViews(); } private void setupViews() { btLogin = (Button) findViewById(R.id.bt_login); btLogin.setOnClickListener(new OnClickListenerImpl()); userEditText = (DeletableEditText) findViewById(R.id.tv_user); psdEditText = (DeletableEditText) findViewById(R.id.tv_psd); tvHideA = (TextView) findViewById(R.id.tvHideA); tvHideB = (TextView) findViewById(R.id.tvHideB); tvHideC = (TextView) findViewById(R.id.tvHideC); tvHideD = (TextView) findViewById(R.id.tvHideD); ivNumA = (ImageView) findViewById(R.id.ivNumA); ivNumB = (ImageView) findViewById(R.id.ivNumB); ivNumC = (ImageView) findViewById(R.id.ivNumC); ivNumD = (ImageView) findViewById(R.id.ivNumD); ivNumA.setOnClickListener(new OnClickListenerImpl()); ivNumB.setOnClickListener(new OnClickListenerImpl()); ivNumC.setOnClickListener(new OnClickListenerImpl()); ivNumD.setOnClickListener(new OnClickListenerImpl()); tvCheck = (TextView) findViewById(R.id.tvCheck); etCheck = (EditText) findViewById(R.id.etCheck); setNum();
Процесс реализации пользовательского EditText:
Мысль:Настройка двух EidtText, в каждом из которых устанавливаются значки. Значок слева - это значок подсказки для учетной записи и пароля, а значок справа - это значок одно-click удаления. Поскольку у значков в EidtText нет события onClick, чтобы реализовать эффект одно-click удаления, необходимо использовать метод обратного вызова OnTouchEvent, чтобы监тировать события нажатия и определить реализацию одно-click удаления. Если учетная запись и пароль пусты, значок одно-click удаления справа устанавливается в режим скрытия, а при наличии символов значок устанавливается в режим отображения. При нажатии на значок справа удаляется символ в текущей строке. Таким образом, реализуется одно-click удаление. Кроме того, при попытке входа в систему, когда учетная запись и пароль пусты, эти строки вибрируют в качестве подсказки.
Не будем говорить больше, давайте сразу перейдем к комментариям в коде, они очень ясны.
пакет com.example.administrator.texttest; import android.content.Context; import android.graphics.drawable.Drawable; import android.text.Editable; import android.text.TextWatcher; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.animation.Animation; import android.view.animation.CycleInterpolator; import android.view.animation.TranslateAnimation; import android.widget.EditText; /** * Создано администратором 10 октября 2015 года. */ public class DeletableEditText extends EditText { private Drawable mRightDrawable; private boolean isHasFocus; public DeletableEditText(Context context) { this(context, null); } public DeletableEditText(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.editTextStyle); } public DeletableEditText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setupViews(); } private void setupViews() { //取的view的上下左右边距 Drawable[] drawables = this.getCompoundDrawables(); //取得right位置的Drawable //即我们在布局文件中设置的android:drawableRight mRightDrawable = drawables[2]; //设置焦点变化的监听 this.setOnFocusChangeListener(new FocusChangeListenerImpl()); //设置EditText文字变化的监听 this.addTextChangedListener(new TextWatcherImpl()); //初始化时让右边clean图标不可见 setClearDrawableVisible(false); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { //当时点击松开时判断点击的位置。这里只进行了X轴方向的判断。 case MotionEvent.ACTION_UP: // Проверка, был ли клик на области значка справа boolean isClean = (event.getX() > (getWidth() - getTotalPaddingRight())) и (event.getX() < (getWidth() - getPaddingRight())); if (isClean) { // Удаление символов setText(""); } break; default: break; } return super.onTouchEvent(event); } private class FocusChangeListenerImpl implements OnFocusChangeListener { @Override public void onFocusChange(View v, boolean hasFocus) { isHasFocus = hasFocus; if (isHasFocus) { boolean isVisible = getText().toString().length() >= 1; setClearDrawableVisible(isVisible); } setClearDrawableVisible(false); } } } // Условие отображения значка clean справа после ввода private class TextWatcherImpl implements TextWatcher { @Override public void afterTextChanged(Editable s) { //Когда есть символы, значение true boolean isVisible = getText().toString().length() >= 1; //Отображение правого значка setClearDrawableVisible(isVisible); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } } // Скрытие или отображение значка clean справа protected void setClearDrawableVisible(boolean isVisible) { Drawable rightDrawable; if (isVisible) { rightDrawable = mRightDrawable; } rightDrawable = null; } // Использование кода для установки значка в правом месте контроллера setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], rightDrawable; getCompoundDrawables()[3]); } // Показ анимации public void setShakeAnimation() { this.startAnimation(shakeAnimation(5)); } // CycleTimes количество повторений анимации public Animation shakeAnimation(int CycleTimes) { // Установка анимации смещения, где new TranslateAnimation(0,10,0,10) четыре значения представляют собой X-координату от 0 до 10, Y-координату от 0 до 10 Animation translateAnimation = new TranslateAnimation(0, 10, 0, 10); // Установка次数 анимации translateAnimation.setInterpolator(new CycleInterpolator(CycleTimes)); // Установка интервала анимации translateAnimation.setDuration(1000); return translateAnimation; } }
Следующие знания необходимо учитывать:
1.Drawable[] drawables = this.getCompoundDrawables(); Получение drawable этого View. Метод getCompoundDrawables() возвращает четыре Drawable объекта, которые соответствуют левому, верхнему, правому и нижнему полям этого View
2.boolean isClean = (event.getX() > (getWidth() - getTotalPaddingRight())) && (event.getX() < (getWidth() - getPaddingRight())); Проверка, находится ли нажатая область в диапазоне правой иконки. где event.getX() это размер X-координаты места нажатия. Подробнее см. рисунок:
3.Анимация перевода translateAnimation = new TranslateAnimation(0, 10, 0, 10); Установка анимации смещения, где new TranslateAnimation(0,10,0,10) четыре значения представляют собой X-координату от 0 до 10, Y-координату от 0 до 10
4. this.setOnFocusChangeListener(new FocusChangeListenerImpl()); Цель установки изменения фокуса - сделать это более человечным. Показывать значок одного клика для удаления только когда фокус на этой строке и есть символы. В противном случае значок скрыт.
5. this.addTextChangedListener(new TextWatcherImpl()); Установка监тора изменений текста. В new TextWatcher{} есть 3 метода. Это:
1).public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
2).public void onTextChanged(CharSequence s, int start, int before, int count) {}
3).public void afterTextChanged(Editable s) {}
Нам нужно добавить реализуемый метод в afterTextChanged(){Editable s}{}. При изменении текста устанавливается отображение правого значка.
TextWatcher { @Override public void afterTextChanged(Editable s) { //Когда есть символы, значение true boolean isVisible = getText().toString().length() >= 1; //Отображение правого значка setClearDrawableVisible(isVisible); }
КапчаПроцесс реализации:
Мысль:Настройка 4 ImageView. Сначала случайным образом генерируется 4 числа от 0 до 10 и хранятся в массиве. Также записывается вся капча. Затем с помощью метода Bitmap.createBitmap преобразуются эти 4 числа в изображения и устанавливаются случайные цвета. При преобразовании каждого числа в изображение случайным образом устанавливается угол поворота, чтобы эти 4 числовых значка были наклонены под определенным углом. Таким образом, капча создается.
Процесс проверки капчи всего лишь имитация: сравнение введенной капчи с записанной. Если они совпадают, то отображается сообщение о правильности, если нет, то о ошибке. Также сбрасывается капча.
Нажатие на область изображения капчи также будет сбрасывать капчу.
Комментарии кода очень详细ные. Давайте посмотрим на код ~~~:
пакет com.example.administrator.texttest; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import java.util.Random; public class MainActivity extends AppCompatActivity { //Кнопка входа private Button btLogin; //Учётная запись private DeletableEditText userEditText; //Пароль private DeletableEditText psdEditText; //Текст чисел кода проверки private TextView tvHideA,tvHideB,tvHideC,tvHideD; //Текст изображения кода проверки private ImageView ivNumA,ivNumB,ivNumC,ivNumD; //Текст для ввода кода проверки private EditText etCheck; //Текст для отображения проверки кода private TextView tvCheck; //Хранение чисел каждого кода проверки private String numStrTmp = ""; //Хранение всего кода проверки private String numStr = ""; //Массив для хранения кода проверки private int[] numArray = new int[4]; // хранящая цвета массива private int[] colorArray = new int[6]; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setupViews(); } private void setupViews() { btLogin = (Button) findViewById(R.id.bt_login); btLogin.setOnClickListener(new OnClickListenerImpl()); userEditText = (DeletableEditText) findViewById(R.id.tv_user); psdEditText = (DeletableEditText) findViewById(R.id.tv_psd); tvHideA = (TextView) findViewById(R.id.tvHideA); tvHideB = (TextView) findViewById(R.id.tvHideB); tvHideC = (TextView) findViewById(R.id.tvHideC); tvHideD = (TextView) findViewById(R.id.tvHideD); ivNumA = (ImageView) findViewById(R.id.ivNumA); ivNumB = (ImageView) findViewById(R.id.ivNumB); ivNumC = (ImageView) findViewById(R.id.ivNumC); ivNumD = (ImageView) findViewById(R.id.ivNumD); ivNumA.setOnClickListener(new OnClickListenerImpl()); ivNumB.setOnClickListener(new OnClickListenerImpl()); ivNumC.setOnClickListener(new OnClickListenerImpl()); ivNumD.setOnClickListener(new OnClickListenerImpl()); tvCheck = (TextView) findViewById(R.id.tvCheck); etCheck = (EditText) findViewById(R.id.etCheck); setNum(); } private void setNum() { initNum(); tvHideA.setText("" + numArray[0]); tvHideA.setTextColor(randomColor()); tvHideB.setText("" + numArray[1]); tvHideB.setTextColor(randomColor()); tvHideC.setText("" + numArray[2]); tvHideC.setTextColor(randomColor()); tvHideD.setText("" + numArray[3]); tvHideD.setTextColor(randomColor()); Matrix matrixA = new Matrix(); //Перестроить матрицу matrixA.reset(); matrixA.setRotate(randomAngle()); Bitmap bmNumA = Bitmap.createBitmap(getBitmapFromView(tvHideA, 20, 50), 0, 0, 20, 50, matrixA, true); ivNumA.setImageBitmap(bmNumA); Matrix matrixB = new Matrix(); //Перестроить матрицу matrixB.reset(); matrixB.setRotate(randomAngle()); Bitmap bmNumB = Bitmap.createBitmap(getBitmapFromView(tvHideB, 20, 50), 0, 0, 20, 50, matrixB, true); ivNumB.setImageBitmap(bmNumB); Matrix matrixC = new Matrix() //Перестроить матрицу matrixC.reset(); matrixC.setRotate(randomAngle()); Bitmap bmNumC = Bitmap.createBitmap(getBitmapFromView(tvHideC,20,50),0,0,20,50,matrixC,true); ivNumC.setImageBitmap(bmNumC); Matrix matrixD = new Matrix(); //Перестроить матрицу matrixD.reset(); matrixD.setRotate(randomAngle()); Bitmap bmNumD = Bitmap.createBitmap(getBitmapFromView(tvHideD,20,50),0,0,20,50,matrixD,true); ivNumD.setImageBitmap(bmNumD); } private Bitmap getBitmapFromView(View v,int width,int height ) { int widSpec = View.MeasureSpec.makeMeasureSpec(width,View.MeasureSpec.EXACTLY); int heiSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY); //Перерисовать размер изображения v.measure(widSpec, heiSpec); // v.layout(0, 0, width, height); Bitmap bitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888); //Нарисовать изображение Canvas canvas = new Canvas(bitmap); v.draw(canvas); return bitmap; } //Установка случайного наклона угла private int randomAngle() { return 20*(new Random().nextInt(5)-new Random().nextInt(3)); } //Случайное генерирование цвета private int randomColor() { colorArray[0]=0xFF000000; //Чёрный colorArray[1] = 0xFFFF00FF; // ФИОТ colorArray[2] = 0xFFFF0000; // КРАСНЫЙ colorArray[3] = 0xFF00FF00; // ЗЕЛЕНЫЙ colorArray[4] = 0xFF0000FF; // СИНЕЯ colorArray[5] = 0xFF00FFFF; // ЦИАН int randomColoId = new Random().nextInt(5); return colorArray[randomColoId]; } // Инициализация кода проверки private void initNum() { numStr=""; numStrTmp=""; for (int i = 0; i < numArray.length; i++) { // Генерация случайного числа от 0 до 10 int numIntTmp = new Random().nextInt(10); // Сохранение каждого кода проверки numStrTmp = String.valueOf(numIntTmp); // Сохранение всего кода проверки numStr = numStr+numStrTmp; numArray[i] = numIntTmp; } } private class OnClickListenerImpl implements View.OnClickListener { @Override public void onClick(View v) { // При нажатии на кнопку входа if(v==btLogin){ // Проверка на пустоту символов счета if (TextUtils.isEmpty(userEditText.getText().toString())){ // При пустоте вибрация уведомления userEditText.setShakeAnimation(); Toast.makeText(MainActivity.this, "Счет или пароль не могут быть пустыми", Toast.LENGTH_SHORT).show(); } // Проверка на пустоту символов пароля if (TextUtils.isEmpty(psdEditText.getText().toString())){ // При пустоте вибрация уведомления psdEditText.setShakeAnimation(); Toast.makeText(MainActivity.this, "Счет или пароль не могут быть пустыми", Toast.LENGTH_SHORT).show(); } //Проверить, правильно ли введен введенный код проверки if(etCheck.getText().toString() != null && etCheck.getText().toString().trim().length() > 0){ tvCheck.setVisibility(View.VISIBLE); if (numStr.equals(etCheck.getText().toString())){ tvCheck.setTextColor(Color.GREEN); tvCheck.setText("Код проверки правильный!"); } else { tvCheck.setTextColor(Color.RED); tvCheck.setText("Ошибка кода проверки!"); etCheck.setText(""); setNum(); } } //Если Onclick не кнопка логина, то остается только изображение кода проверки с событием прослушивания. Это эквивалентно клику по изображению кода проверки. Изменить код проверки. } else { setNum(); tvCheck.setVisibility(View.GONE); } } } }
Важно учитывать:
1.Bitmap.createBitmap(getBitmapFromView(tvHideA, 20, 50), 0, 0, 20, 50, matrixA, true);
Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
Bitmap source: исходное bitmap, из которого нужно сделать вырез
int x: начальная координата x
int y: начальная координата y
int width: ширина изображения, которое нужно вырезать
int height: высота изображения, которое нужно вырезать
boolean filter При выполнении не только трансформации перемещения, параметр filter принимает значение true для выполнения фильтрации, что помогает улучшить качество нового изображения; при false компьютер не выполняет фильтрацию.
2.intwidSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int heiSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
Установить ширину и высоту View. View.MeasureSpec.EXACTLY означает установку размера View по фактическому размеру. То есть前面的 width(height) равен有多大, настолько и будет.
3.Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888); Создать значок.
4.Canvas canvas =newCanvas(bitmap);
v.draw(canvas); Нарисовать изображение
5.v.measure(widSpec, heiSpec);
//v.layout(0,0, width, height); Перерисовать размер изображения.
Далее будут изображения работы в режиме выполнения:
Когда есть ввод, значок一键删除 справа отображается, когда теряется фокус, значок一键 удаления исчезает, щелкните для обновления капчи:
Далее не будет подробных иллюстраций.
Загрузка исходного кода:http://xiazai.jb51.net/201610/yuanma/Androidlogin(jb51.net).rar
Вот и все, что есть в этой статье, я надеюсь, что это поможет вам в изучении, и希望大家多多支持呐喊教程。
Заявление: содержимое этой статьи взято из Интернета, авторские права принадлежат соответствующему автору, контент предоставлен пользователями Интернета, сайт не имеет права собственности, не был отредактирован вручную, и не несет ответственности за соответствующие юридические вопросы. Если вы обнаружите подозрительное содержимое о нарушении авторских прав, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (во время отправки письма замените # на @) для отчета и предоставьте соответствующие доказательства. Как только будет установлено, что это правда, сайт немедленно удалит подозрительное содержимое, нарушающее авторские права.