I'm trying to wrote android program which displays Greatest Common Divisor of two integers specified in two different EditText fields. First I've done it with button, everything worked (you can see onclick listener commented out in code below). Now I want to do this: app checks when both EditTexts are not empty and then automatically starts calculating and shows gcd. Buty app crashes when I start typing in any of EditText fields. Also I tried to add TextChangeListener only on one of EditTexts. Everything is good until I delete all input from one of the fields, then app crashes again. I'm only starting to understand android development and made this app mostly by modifying examples found on internet so maybe I did something wrong... Can anyone help me? Thanks
MainActivity.java
public class MainActivity extends Activity
{
EditText a;
EditText b;
TextView gcdResult;
Button calculateGcd;
int a, b, gcdValue
TextWatcher textWatcher = new TextWatcher(){
#Override
public void afterTextChanged(Editable s){}
#Override
public void beforeTextChanged(CharSequence s,int start, int count, int after){}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count){
AutoCalculateGcd();
}
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
a = (EditText)findViewById(R.id.aText1);
b = (EditText)findViewById(R.id.bText1);
gcdResult = (TextView)findViewById(R.id.resultTextView1);
calculateGcd = (Button)findViewById(R.id.calcButton1);
/* calculateGcd.setOnClickListener(new OnClickListener(){
public void onClick(View v){
AutoCalculateRatio();
}
});*/
a.addTextChangedListener(textWatcher);
b.addTextChangedListener(textWatcher);
}
//Euclidean alghorithm to find gcd
public static int gcd(int a, int b) {
if (b == 0) return w;
else return gcd(b a % b);
}
public static boolean isInputNotEmpty(EditText a, EditText b){
String a = a.getText().toString();
String b = b.getText().toString();
if(a.equals("") && b.equals("") ){
return false;
}
else{
return true;
}
}
public void AutoCalculateGcd(){
if(isInputNotEmpty(a, b)){
a = Integer.parseInt(width.getText().toString());
b = Integer.parseInt(height.getText().toString());
gcdValue = gcd(a, b);
ratioResult.setText(Integer.toString(gcdValue));
}
else{
//Toast.makeText(this, "No input", Toast.LENGTH_SHORT).show();
}
}
}
Actually, you should replace
public static boolean isInputNotEmpty(EditText a, EditText b) {
String a = a.getText().toString();
String b = b.getText().toString();
if (a.equals("") && b.equals("")) {
return false;
}
else {
return true;
}
}
with
public static boolean isInputNotEmpty(EditText a, EditText b) {
String a = a.getText().toString();
String b = b.getText().toString();
if (a.equals("") || b.equals("")) {
return false;
}
else {
return true;
}
}
Or even
public static boolean isInputNotEmpty(EditText a, EditText b) {
return !(a.getText().toString().isEmpty() || b.getText().toString().isEmpty());
}
Because you want to know if any ( || ) of them is empty, not if both (&&) are.
It might help if you post the stacktrace, but my guess is that you are getting a NumberFormatException from the Integer.parseInt() calls. One approach would be to do something like:
try {
a = Integer.parseInt(width.getText().toString());
b = Integer.parseInt(height.getText().toString());
gcdValue = gcd(a, b);
ratioResult.setText(Integer.toString(gcdValue));
} catch ( NumberFormatException e) {
ratioResult.setText("N/A")
}
Related
I have multiple EditTexts and I want to change the input of all of them at the same time, as I modify only one.(all of them take decimal numbers as input)
I stored the EditTexts in an array named 'editTexts'.
Here's what I tried
//Set the listener for each element
for (int i=0; i<editTexts.length; i++) {
final int finalI = i;
editTexts[i].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 the editText which is currently edited is empty, set the input for all the rest to be '0.0'
if (editTexts[finalI].getText().toString().trim().length() == 0) {
for(EditText e : editTexts) {
if (e == editTexts[finalI])
continue;
e.setText("0.0");
}
} else {
float no = Float.parseFloat(s.toString() + "");
//Set the input of all the other editTexts to be the decimal number entered, multiplied by 2
for(EditText e : editTexts){
if(e == editTexts[finalI])
continue;
e.setText(no*2+"");
}
}
}
#Override
public void afterTextChanged(Editable s) {
}
})
}
In this case the multiplication coefficient is just an example, it's not always gonna be 2. I used it just to test it out.
For some reason, when I change the input value, the app freezes.
Any help? Thanks!
Use LiveData to store your user input values.
Once it's value changes you can set value to each EditText. I think it is an easy way to implement.
Try it like this:
// et_x1, et_x2 and et_x3 are ids of EditTexts
//set inputType for all EditTexts as numberDecimal
EditText editText1 = findViewById(R.id.et_x1);
final EditText editText2 = findViewById(R.id.et_x2);
final EditText editText3 = findViewById(R.id.et_x3);
editText1.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) {
String value = s.toString();
double x;
if (!value.equals("")) {
x = Double.parseDouble(value);
} else {
x = 0.0;
}
editText2.setText(Editable.Factory.getInstance().newEditable((String.valueOf(Math.pow(x, 2)))));
editText3.setText(
Editable.Factory.getInstance().newEditable((String.valueOf(Math.pow(x, 3)))));
}
#Override
public void afterTextChanged(Editable s) {
}
});
Hope it helps you!
public class Cari extends AppCompatActivity implements TextWatcher,View.OnClickListener {
TextView hasil, teks, teks2;
AutoCompleteTextView edit;
Button prev, terpilih;
String[] item = { "Matahari","Merkurius","Venus","Bumi","Mars","Yupiter","Saturnus","Uranus","Neptunus" };
hasil = findViewById(R.id.hasil);
edit = findViewById(R.id.edit);
edit.addTextChangedListener(this);
edit.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, item));
teks = findViewById(R.id.title);
Typeface customfont = Typeface.createFromAsset(getAssets(), "font/Starjout.ttf");
teks.setTypeface(customfont);
teks2 = findViewById(R.id.titleDes);
Typeface customfont2 = Typeface.createFromAsset(getAssets(), "font/Starjout.ttf");
teks2.setTypeface(customfont2);
terpilih = findViewById(R.id.pilih);
terpilih.setOnClickListener(this);
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
edit.getText();
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//not used
}
public void afterTextChanged(Editable s) {
//not used
}
public void onClick(View a) {
switch (a.getId()) {
case R.id.pilih:
Toast.makeText(this, "Kamu memilih Planet "+edit.getText(), Toast.LENGTH_SHORT).show();
mpilih();
break;
}
}
private void mpilih() {
if (//what statement should add) {
//here too *hasil.setText();
}
else {
//here too
}
}
How to make if else statement and set TextView hasil to get res/value/string name sun
this my first time programming using android studio, so i don't know too much about java mobile code. And sorry for bad English. Hope you understand
Use getText() to get AutoCompleteTextView value.
Here's the example of checking condition if AutoCompleteTextView is empty.
private void mpilih() {
if (!TextUtils.isEmpty(edit.getText())) {
hasil.setText(getString(R.string.sun));
} else {
edit.setError("Please enter your selection");
}
}
If you're using only those fixed item as selection, i suggest you use Spinner instead..
EDIT
For multiple 'if' you can use it like this
if (edit.getText().equals("Matahari")) {
hasil.setText(getString(R.string.sun));
} else if (edit.getText().equals("Bumi"){
hasil.setText(getString(R.string.earth));
}
I have a form. I want to display a calculation in "live time" when the user enters different values into some int fields. I made my Activity implement the TextWatcher interface and set a listener on 3 different EditText fields but it appears the Textwatcher only detects the first EditText declared in the Activity's code.
You can see from the code below, I'm trying to grabe a few fields, convert them to ints and display the output in an EditText field at the bottom of the form. Where am I going wrong? Do I need to implement a textWatcher individually on all of the EditText fields involved? That would be a rather verbose solution making my code a lot longer than I would like
public class NewStageFormActivity extends AppCompatActivity implements TextWatcher{
Context mContext;
EditText mStageName, mPaperTargets, mHitsPerTarget, mSteelTargets, mSteelNPMs, mOutput;
Spinner mScoringType, mStrings;
CheckBox mNoShoots, mNPMs;
Button mSaveButton;
Match mGlobalMatch;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stage_form);
mContext = this;
mGlobalMatch = GlobalMatch.getMatch();
mStageName = (EditText)findViewById(R.id.stage_name_et);
mPaperTargets = (EditText)findViewById(R.id.paper_targets_et);
mHitsPerTarget = (EditText)findViewById(R.id.hits_per_target_et);
mSteelTargets = (EditText)findViewById(R.id.steel_targets_et);
mSteelNPMs = (EditText)findViewById(R.id.steel_npm_et);
mScoringType = (Spinner)findViewById(R.id.scoring_type_spinner);
mStrings = (Spinner)findViewById(R.id.strings_spinner);
mNoShoots = (CheckBox)findViewById(R.id.no_shoots_cb);
mNPMs = (CheckBox)findViewById(R.id.npm_cb);
mSaveButton = (Button)findViewById(R.id.save_button);
mOutput = (EditText)findViewById(R.id.output_et);
// paper * hitsPer + steel
mPaperTargets.addTextChangedListener(this);
mSteelTargets.addTextChangedListener(this);
mSteelTargets.addTextChangedListener(this);
mSaveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(mStageName.getText().toString().equals("") || mPaperTargets.getText().toString().equals("") ||
mHitsPerTarget.getText().toString().equals("") || mSteelTargets.getText().toString().equals("") ||
mSteelNPMs.getText().toString().equals("")){
Toast.makeText(mContext, "You must fill in all form fields", Toast.LENGTH_SHORT).show();
} else {
String name = mStageName.getText().toString();
String type = mScoringType.getSelectedItem().toString();
int strings = Integer.valueOf(mStrings.getSelectedItem().toString());
int paperTargets = Integer.valueOf(mPaperTargets.getText().toString());
int hitsPerTarget = Integer.valueOf(mHitsPerTarget.getText().toString());
boolean noShoots;
boolean npms;
if(mNoShoots.isChecked()){
noShoots = true;
} else {
noShoots = false;
}
if(mNPMs.isChecked()){
npms = true;
} else {
npms = false;
}
int steelTargets = Integer.valueOf(mSteelTargets.getText().toString());
int steelNPMs = Integer.valueOf(mSteelNPMs.getText().toString());
MatchStage matchStage = new MatchStage(name, type, strings, paperTargets, hitsPerTarget,
noShoots, npms, steelTargets, steelNPMs);
mGlobalMatch.getStages().add(matchStage);
String jsonString = new Gson().toJson(mGlobalMatch);
MatchHelper.updateFile(mContext, MatchHelper.createFileName(mGlobalMatch.getMatchId()),
jsonString);
Intent intent = new Intent(mContext, StagesListActivity.class);
startActivity(intent);
}
}
});
}
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
int paper = Integer.valueOf(mPaperTargets.getText().toString());
int hitsPer = Integer.valueOf(mHitsPerTarget.getText().toString());
int steel = Integer.valueOf(mSteelTargets.getText().toString());
int minRound = (paper * hitsPer) + steel;
int points = minRound * 5;
mOutput.setText("Minimum rounds: " + (minRound) + "\t\t Points: " + points);
}
#Override
public void afterTextChanged(Editable editable) {
}
}
In my experience I've had issues with using the same TextWatcher on multiple EditText. You could get around this by creating a method that produces a new instance of TextWatcher for each EditText so your code isn't all verbose. Try something like this:
Get rid of implements TextWatcher for your Activity and it's associated methods. Implement a method createTextWatcher():
private TextWatcher createTextWatcher() {
return new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
// Copy your original code
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
// Copy your original code
}
#Override
public void afterTextChanged(Editable editable) {
// Copy your original code
}
};
}
Now to use it like this:
mPaperTargets.addTextChangedListener(createTextWatcher());
mSteelTargets.addTextChangedListener(createTextWatcher());
The most up-voted answer on #Natan Felipe's link also demonstrates using one instance of TextWatcher per EditText.
I'm having problems to get the position of my View inside a ListView when TextWatcher triggers for changes in EditText.
Each CardView has two EditTexts and two Spinners. When I make some change in the values for the name of the product (the EditText in the left) and for the spinners, my code get the correctly the position of the CardView in the list.
However, when I change the value of the price by typing it, my code cannot get it's position.
The position of the CardView is gotten in the line...
final int posicao = Integer.parseInt(consumableInfo.getName()), which consumableInfo is the class listed in my Adapater, and consumableInfo.getName gets the name of the card, which is equal to the position of the card. Like "0", "1", "2"...
This happens because everytime I call...
holder.mAutoCompleteTextView.setOnItemClickListener for the AutoCompleteEditText on the left;
holder.mDivideConsumableSpinner.setOnItemSelectedListener for each spinner;
...my code iterates again over BindData. However, when I call...
holder.mConsumablePriceTextView.addTextChangedListener(priceTextWatcher) for the EditText on the right;
... my code DO NOT iterates again.
I'm trying to find another way to get it's position, but I'm having problems with that. Maybe forcing a way to posicao get the value, or creating a customTextWatcher that implements TextWatcher and gets consumableInfo as a parameter.
public class ConsumableAdapter extends RecyclerView.Adapter<ConsumableAdapter.ConsumableViewHolder> {
/*...some code ommited...*/
int posicaoGlobal;
public ConsumableAdapter(Context context, List<ConsumableInfo> contactList) {...}/*...some code ommited...*/
}
public class ConsumableViewHolder extends RecyclerView.ViewHolder {
public AutoCompleteTextView mAutoCompleteTextView;
public Spinner mDivideConsumableSpinner;
public Spinner mUnitsConsumableSpinner;
public EditText mConsumablePriceTextView;
public ConsumableViewHolder(View itemView) {
/*...*/
}
public void bindData(ConsumableInfo consumableInfo, ConsumableViewHolder holder, Context context) {
final int posicao = Integer.parseInt(consumableInfo.getName());
posicaoGlobal = posicao;
ArrayAdapter adapter = new ArrayAdapter(mContext, android.R.layout.select_dialog_item,
Constants.CONSUMABLE_CONSTANTS);
holder.mAutoCompleteTextView.setAdapter(adapter);
/* position is updated withmAutoCompleteTextView.setOnItemClickListener */
holder.mAutoCompleteTextView.setOnItemClickListener(new AdapterView.OnItemClickListener({
updateTotalPrice(posicao);
/*...*/
});
/*position is NOT updated with addTextChangedListener*/
holder.mConsumablePriceTextView.addTextChangedListener(priceTextWatcher);
/*position is updated with setOnItemSelectedListener in both Spinners*/
holder.mDivideConsumableSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
updateTotalPrice(posicao);
/*...*/
});
//product units
holder.mUnitsConsumableSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
updateTotalPrice(posicao);
/*...*/
});
}
private void updateTotalPrice(int posicao) {
/*...*/
mTotalPrice = getTotalPrice(BotequimActivity.mProductList, mPercent);
BotequimActivity.mTotalPriceTextView.setText(getTotalPriceString());
FormatStringAndText.setPriceTextViewSize(mTotalPrice, BotequimActivity.mTotalPriceTextView);
}
}
private void updateTotalPrice(int posicao, String priceString) {
/*...*/
BotequimActivity.mTotalPriceTextView.setText(getTotalPriceString());
FormatStringAndText.setPriceTextViewSize(mTotalPrice, BotequimActivity.mTotalPriceTextView);
}
private final TextWatcher priceTextWatcher = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (count != 0) {
if (FormatStringAndText.isNumeric(s.toString())) {
mProductPriceBeforeChange = Double.parseDouble(s.toString());
}
}
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Toast.makeText(mContext, "posicao =" + posicaoGlobal, Toast.LENGTH_SHORT).show();
if (s.toString().length() == 0) {
updateTotalPrice(posicaoGlobal, "0.00");
} else {
if (!isAutoCompleteClicked) {
if (FormatStringAndText.isNumeric(s.toString())) {
mProductPriceAfterChange = Double.parseDouble(s.toString());BotequimActivity.mTotalPriceTextView.setText(getTotalPriceString());
// FormatStringAndText.setPriceTextViewSize(mTotalPrice, BotequimActivity.mTotalPriceTextView);
updateTotalPrice(posicaoGlobal, s.toString());
} else {
}
} else {
isAutoCompleteClicked = false;
}
}
}
#Override
public void afterTextChanged(Editable s) {
}
};
public Double getTotalPrice(ArrayList<Product> productList, Double percent) {
mTotalPrice = 0;
for (Product product : productList) {
mTotalPrice = mTotalPrice + percent * (product.getUnits() * (product.getDoublePrice()) / product.getDividedBy());
}
return mTotalPrice;
}
}
You need to save the position when you create the TextWatcher. I would do this with an inner subclass:
// this is an inner class so it will have an implicit reference to
// the adapter (ConsumableAdapter.this)
public class PriceTextWatcher implements TextWatcher {
private int mPos;
public PriceTextWatcher(int position) {
super();
mPos = position;
}
// now add your TextWatcher implementation here and use mPos for position
#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) {}
}
Now you can initialize the position when you create the TextWatcher:
holder.mConsumablePriceTextView.addTextChangedListener(new PriceTextWatcher(posicao));
You will have multiple TextWatchers instead of the single final TextWatcher you currently have, but that's the trade-off for getting the position value where it needs to be.
Solved. I had to call priceTextWatcher as an argument with it's constructor, just like AdapterView.OnItemSelectedListener(). The correct one is:
holder.mConsumablePriceTextView.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//...
}
//...methods inside here
}
i use a TextWatcher to change pressed key value. my goal is that replace some characters while typing. for example when i type keys, if reached "S" character, replaces it with "a" character. my question is: should i do it in beforeTextChanged?? how? can anyone give me an example?
I know that this post is a couple of years old, but both versions did not work for me and have build a hybrid between the two answers.
#Override
public void afterTextChanged(Editable editable) {
if (editable.toString().contains(",")) {
Editable ab = new SpannableStringBuilder(editable.toString().replace(",", ""));
editable.replace(0, editable.length(), ab);
}
}
Using beforeTextChanged won't be useful because it won't interrupt the actual printing of the key to the EditText. I would use something similar to:
public void afterTextChanged(Editable s) {
if(s.length() > 0 && s.toString().charAt(s.length()-1) == 'S')
{
final String newText = s.toString().substring(0, s.length()-1) + "a";
editText.setText(newText);
}
}
I added some toString()'s, not 100% sure how Editable works but I think that should cover it.
You have to do it in the afterTextChanged, but don't forget to detach
and reattach the TextChangedListener to prevent an endless loop.A simple example is shown below :
public void afterTextChanged(Editable s) {
editText.removeTextChangedListener(this);
//.. do changes here ..//
editText.setText(newText);
editText.addTextChangedListener(this);
}
But there is another problem when you call setText, it causes the cursor to move to the end of the text inside the textView. So you have to calculate the new position for the curser yourself, remember user may enter the multiple characters at once by pasting or delete a selected part of the text.Here is a more complete example. This watcher class removes all nonnumeric characters of the text.
public class NumWatcher implements TextWatcher {
private EditText editText;
private int selPos;
private String oldString, newString;
public NumWatcher(EditText editText) {
this.editText = editText;
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
selPos = editText.getSelectionStart();
oldString = myFilter(s.toString());
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
editText.removeTextChangedListener(this);
newString = myFilter(s.toString());
editText.setText(newString);
int newPos = selPos + (newString.length() - oldString.length());
if (newPos < 0) newPos = 0;
editText.setSelection(newPos);
editText.addTextChangedListener(this);
}
public String myFilter(String s) {
String digits;
digits = s.replaceAll("[^0-9]", "");
if (s.equals("")) return "";
return digits;
}
}
#Override
public void afterTextChanged(Editable arg0) {
Editable ab = new SpannableStringBuilder(arg0.toString().replace("S", "a"));
arg0 = ab ;
}