2016-06-29 2 views
4

Я пытаюсь создать простую форму кредитной/дебетовой карты. У меня есть поле CardNumber EditText. Когда пользователь начнет вводить текст, я хочу, чтобы мое приложение вставляло пробел после каждых 4 цифр. Я получил помощь от учебника this и немного изменил его, но он не работает. Он не входит в пространство после каждых 4 цифр.Android afterTextChanged не будет вводить пробел после каждых четырех символов

MainActivity.java

package ************************* 

import android.content.pm.ActivityInfo; 
import android.os.Bundle; 
import android.support.design.widget.FloatingActionButton; 
import android.support.design.widget.Snackbar; 
import android.support.v7.app.AppCompatActivity; 
import android.support.v7.widget.Toolbar; 
import android.text.Editable; 
import android.text.TextUtils; 
import android.text.TextWatcher; 
import android.view.KeyEvent; 
import android.view.View; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.widget.EditText; 

import java.security.Key; 

public class MainActivity extends AppCompatActivity { 

    private EditText cardNumber, expiryDate, CVV, nameOnCard; 

    private boolean flag = false; 


    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 
     setSupportActionBar(toolbar); 
     setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);//Locks the screen orientation 
     init(); //Initializes the variables 

     typefunc(); 

    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.menu_main, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     // Handle action bar item clicks here. The action bar will 
     // automatically handle clicks on the Home/Up button, so long 
     // as you specify a parent activity in AndroidManifest.xml. 
     int id = item.getItemId(); 

     //noinspection SimplifiableIfStatement 
     if (id == R.id.action_settings) { 
      return true; 
     } 

     return super.onOptionsItemSelected(item); 
    } 

    public void init() 
    { 
     cardNumber = (EditText) findViewById(R.id.cardNumber); //Field for storing the card number 
     expiryDate = (EditText) findViewById(R.id.expiryDate); //For storing the Expiry Date 
     CVV = (EditText) findViewById(R.id.CVV); //For storing the CVV 
     nameOnCard = (EditText) findViewById(R.id.nameOnCard); //For storing the name of the Cardholder 
    } 

    public void typefunc() 
    { 
     cardNumber.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) 
      { 

       if(s.length()==16) 
       { 
        expiryDate.setVisibility(View.VISIBLE); 
        expiryDate.requestFocus(); 
        CVV.setVisibility(View.VISIBLE); 
       } 
      } 

      @Override 
      public void afterTextChanged(Editable s) 
      { 

       char space = ' '; 

       if (s.length() > 0 && (s.length() % 5) == 0) 
       { 
        char c = s.charAt(s.length() - 1); 

        if (Character.isDigit(c)) 
        { 
         s.insert(s.length() - 1, String.valueOf(space)); 
        } 
       } 
      } 
     }); 

     expiryDate.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) 
      { 
       if(s.length()==6) 
        CVV.requestFocus(); 
      } 

      @Override 
      public void afterTextChanged(Editable s) { 

      } 
     }); 

     CVV.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) 
      { 
       if(s.length()==3) { 
        nameOnCard.setVisibility(View.VISIBLE); 


       } 
      } 

      @Override 
      public void afterTextChanged(Editable s) 
      { 
       if(s.length()==3) 
        nameOnCard.requestFocus(); 
      } 
     }); 
    } 

} 
+0

Вы хотите пространство, когда пользователь изменяет содержимое не на е он завершен правильно ?! Так почему бы не поместить его в onTextChanged – silverFoxA

+0

's.length()% 5' возвращает' 0', если 's.length()' кратно '5', а не' 4'. – Titus

+0

@silverFoxA Вам не разрешено изменять содержимое 's' из' onTextChanged() '. Это можно сделать только из 'afterTextChanged()'. – Auro

ответ

3

Это работает отлично

editText.addTextChangedListener(new TextWatcher() { 
    private static final char space = ' '; 

    @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) { 
     // Remove spacing char 
     if (s.length() > 0 && (s.length() % 5) == 0) { 
      final char c = s.charAt(s.length() - 1); 
      if (space == c) { 
       s.delete(s.length() - 1, s.length()); 
      } 
     } 
     // Insert char where needed. 
     if (s.length() > 0 && (s.length() % 5) == 0) { 
      char c = s.charAt(s.length() - 1); 
      // Only if its a digit where there should be a space we insert a space 
      if (Character.isDigit(c) && TextUtils.split(s.toString(), String.valueOf(space)).length <= 3) { 
       s.insert(s.length() - 1, String.valueOf(space)); 
      } 
     } 
    } 
}); 

и Дон» t забыл добавить ниже атрибуты к edittext

android:inputType="phone" android:maxLength="19" 

надеюсь, что это помогает :)

+0

это работает как шарм. спасибо –

0

Это из-за afterTextChanged()

afterTextChanged() - Это после того, как Выполнение выражений текст изменился!
Этот метод вызван, чтобы уведомить вас, что где-то в s текст был изменен.

onTextChanged() - Это в то время как Выполнение выражений текст меняется
Этот метод вызывается, чтобы уведомить вас, что в течение секунд, количество символов, начиная с начала только заменить старый текст, который имел длину до этого.
Подробнееhere

Так что у мог бы сделать что-то вроде:

cardNumber.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) 
    { 
     if(cardNumber.length() == 4) 
     { 
      cardNumber.setText(cardNumber.getText() + " "); 
     } 
    } 

    @Override 
    public void afterTextChanged(Editable s) 
    { 

    } 
}); 

Примечание:setText() также запустит onTextChanged(), но поскольку длина теперь 5 она должна не имеет значения.

+0

Из документации 'onTextChanged()': «Ошибка при попытке внести изменения в' s' из этого обратного вызова ». Проверьте этот ответ также: http: // stackoverflow.com/a/6003815/3363481 – earthw0rmjim

+0

Я не понимаю ур точку? 'onTextChanged()' используется для немедленного изменения текста (при изменении текста) – Strider

+0

Нет, это не для изменения текста, а для наблюдения за изменениями. – earthw0rmjim

0

удалить вам код из метода afterTextChanged и из него в OnTextChanged способом, как показано ниже,

 @Override 
     public void onTextChanged(CharSequence s, int start, int before, int count) 
     { 

      char space = ' '; 

      if (s.length() > 0 && (s.length() % 5) == 0) 
      { 
       char c = s.charAt(s.length() - 1); 

       if (Character.isDigit(c)) 
       { 
        //s.insert(s.length() - 1, String.valueOf(space)); 
        cardNumber.append(String.valueOf(space)); 
       } 
      } 


      if(s.length()==16) 
      { 
       expiryDate.setVisibility(View.VISIBLE); 
       expiryDate.requestFocus(); 
       CVV.setVisibility(View.VISIBLE); 
      } 
     } 
+0

'insert()' function is ** NOT ** разрешено с 'onTextChanged()' – Auro

+0

использовать напрямую cardNumber.setText() вместо вставки проверить мой ответ – Vickyexpert

0

Попробуйте это:

cardNumber.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) { 
      if(s.length()==16) { 
       expiryDate.setVisibility(View.VISIBLE); 
       expiryDate.requestFocus(); 
       CVV.setVisibility(View.VISIBLE); 
      } 
     } 

     @Override 
     public void afterTextChanged(Editable s) { 
      String txt = s.toString(); 
      s.clear(); 
      s.insert(0, txt.replaceAll("\\D","").replaceAll("(\\d{4}(?!$))","$1-")); 
     } 
    });