Get position of element in listview when TextWatcher triggers - java

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
}

Related

How to get string text from AutoCompleteTextView using if else?

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));
}

Can I use The same TextWatcher on different EditText widgets

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.

Overwrite text in EditText that has only 1 char is not working

I have multiple EditText views , each EditText view can contain only 1 char.
I need to make this rule - if I focus on one EditText , and it already has some text inside - then overwrite it . Also - if I press on delete key - I need the text to be cleared inside that view.
Then - I am checking if the EditText views has 1 empty cell - if not - checking if the EditText views has the correct letters.
I could have managed to make the clear button work, but I can not make the overwrite.
I did tried to use the TextWatcher , but it didn't work for me.
The EditText views are created dynamically .
Here is my code :
Answer.java
public class Answer {
String answer;
int answer_length;
int cell_margin=10;
int cell_size=180;
EditText[] EditTextArray;
public Answer(RelativeLayout rLayout1, Context context , String answer) {
this.answer = answer;
answer_length = answer.length();
if (answer_length>6){
cell_margin = 4;
cell_size = 110;
}
EditTextArray = new EditText[answer_length];
AnswerCell EditTextToSeeFirst = new AnswerCell(context,cell_size);
setListener(EditTextToSeeFirst);
EditTextArray[0] = EditTextToSeeFirst;
RelativeLayout.LayoutParams fparams = new RelativeLayout.LayoutParams
(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
fparams.setMargins(cell_margin,0,cell_margin,0);
rLayout1.addView(EditTextToSeeFirst, fparams);
for (int i = 1; i<answer_length ; i++){
RelativeLayout.LayoutParams lparams = new RelativeLayout.LayoutParams
(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
lparams.addRule(RelativeLayout.LEFT_OF, EditTextArray[i-1].getId());
lparams.setMargins(cell_margin,0,cell_margin,0);
AnswerCell newEditText = new AnswerCell(context,cell_size);
setListener(newEditText);
EditTextArray[i] = newEditText;
rLayout1.addView(EditTextArray[i], lparams);
}
rLayout1.setGravity(Gravity.CENTER );
}
public void setListener(AnswerCell ac){
ac.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.d("test","test");
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
goToNextAvailableCell();
}
});
}
public void goToNextAvailableCell(){
for (int i = 0; i<answer_length ; i++) {
if(EditTextArray[i].getText().toString().matches("")){
EditTextArray[i].requestFocus();
return;
}
}
//Did not found empty cell
checkCorrectAnswer();
}
private void checkCorrectAnswer(){
String tryAnswer = "";
for (int i = 0; i<answer_length ; i++) {
tryAnswer += EditTextArray[i].getText().toString();
}
if (tryAnswer.matches(answer)){
Log.d("Correct !!","Correct Answer");
}
}
}
AnswerCell.java
public class AnswerCell extends EditText{
public AnswerCell(final Context context, int cell_size) {
super(context);
this.setId(View.generateViewId());
this.setBackgroundResource(R.color.answerCellBackground);
this.setHeight(cell_size);
this.setWidth(cell_size);
this.setFilters(new InputFilter[] {new InputFilter.LengthFilter(1)});
this.setCursorVisible(false);
this.setGravity(Gravity.CENTER);
this.setOnFocusChangeListener( new View.OnFocusChangeListener(){
public void onFocusChange( View view, boolean hasfocus){
if(hasfocus){
view.setBackgroundResource( R.drawable.answer_cell_has_focus);
}
else{
view.setBackgroundResource( R.drawable.answer_cell_lost_focus);
}
}
});
this.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
//You can identify which key pressed buy checking keyCode value with KeyEvent.KEYCODE_
if(keyCode == KeyEvent.KEYCODE_DEL) {
((EditText)v).setText("");
return true;
}
return false;
}
});
}
}
thanks !
It will work with this code
TextWatcher watcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//YOUR CODE
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//YOUR CODE
}
#Override
public void afterTextChanged(Editable s) {
String outputedText = s.toString();
// mOutputText.setText(outputedText);
}
};
Then add this in oncreate
mInputText.addTextChangedListener(watcher);
e2.addTextChangedListener(watcher);
e3.addTextChangedListener(watcher);
e4.addTextChangedListener(watcher);

EditText's onTextChanged being called with empty value on row recycle

I have a RecyclerView with an EditText in each row. Each EditText has a TextWatcher attached to it and an object in an array to store information about the row and the value of the EditText.
The problem I'm facing is that when the row goes offscreen, it gets recycled, but in that process, onTextChanged is called with an empty string, meaning an empty string is being saved to the row's information object. When that row is loaded again, it just loads a blank value, effectively deleting whatever content was in the EditText before. This seems like very useless functionality, because (as far as I can tell) there's no way to differentiate between a recycle clear and the user actually clearing the value in the EditText, making EditTexts in a RecyclerView completely useless.
my onBindViewHolder method is this:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int value = indicators.get(position).getValue();
System.out.println("VALUE: " + indicator.getValue());
if (value == -1) {
viewHolder.inputBox.setText("");
} else {
viewHolder.inputBox.setText(Integer.toString(value));
}
viewHolder.editListener.updatePosition(position);
}
My TextWatcher is this:
private class EditBoxListener implements TextWatcher {
private int position;
private CharSequence sequence;
private boolean initialCall = true;
public void updatePosition(int _position) {
position = _position;
}
#Override
public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {}
#Override
public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
System.out.println("TEXT CHANGED TO: " + charSequence.toString());
if (!initialCall) {
int value = -1;
try {
value = Integer.parseInt(charSequence.toString());
} catch (Exception e) {}
if (indicators.size() > 0) {
indicators.get(position).setValue(value);
}
} else {
initialCall = false;
}
}
#Override
public void afterTextChanged(Editable editable) {}
}
Well one way to combat this would be to simply check if the text is blank or not before doing anything with it, perhaps something like this (forgive my poor formatting):
#Override
public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
if (!charSequence.equals("")) {
System.out.println("TEXT CHANGED TO: " + charSequence.toString());
if (!initialCall) {
int value = -1;
try {
value = Integer.parseInt(charSequence.toString());
} catch (Exception e) {}
if (indicators.size() > 0) {
indicators.get(position).setValue(value);
}
} else {
initialCall = false;
}
}
}

(android textwatcher)how to push a textWatcher on firebase

I am doing a chat app and got stocked on how to make textWatcher which will push on the firebase data structure under user-typing
. I want to push a data structure wherein on the data structure you will see if the user is typing. when the user is typing the data structure under user-typing is true. if the user is not typing then it will become false. i tried this code but it seems wrong because every time i run the program. When I click the ediText. it will automatically make a data structure key for a user
final Firebase test = firebase.child("room-typing").push();
test.setValue("true");
final EditText editText = (EditText) findViewById(R.id.editText);
editText.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (s == editText) {
firebase.child("room-typing").child(test.getKey()).child("test").setValue("true");
} else {
firebase.child("room-typing").child(test.getKey()).child("test").setValue("false");
}
}
});
You're creating that new key yourself, by calling push(). From the documentation for push():
Generates a new child location using a unique key and returns a Firebase reference to it.
I added some comments to you code, to mark where things happen:
// This next line creates a new key
final Firebase test = firebase.child("room-typing").push();
test.setValue("true");
final EditText editText = (EditText) findViewById(R.id.editText);
editText.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (s == editText) {
// This next line uses the new key you created above
firebase.child("room-typing").child(test.getKey()).child("Onediver").setValue("true");
} else {
// As does the next line here
firebase.child("room-typing").child(test.getKey()).child("Onediver").setValue("false");
}
}
});
To prevent the creation of a new child, you should not call push, but depend on a known child, such as:
final Firebase test = firebase.child("room-typing").child("jaymee");
There are 2 ways you can do this. An easy way and there is an elegant way.
For elegant way look into: http://reactivex.io/documentation/operators/debounce.html
Here's the easy way:
Create somewhere a custom countdown timer:
public class MyCountDownTimmer extends CountDownTimer {
public MyCountDownTimmer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override public void onTick(long l) {
}
#Override public void onFinish() {
databaseReference.child("room-typing").child(room_name).child(user_id_or_name).setValue("false");
isTyping = false;
}
}
Declare your countdown timer
private MyCountDownTimmer isTypingTimmer = new MyCountDownTimmer(1000, 1000);
private boolean isTyping = false;
editText_message.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
isTypingTimmer.cancel();
isTypingTimmer.start();
if (!isTyping) {
databaseReference.child("room-typing").child(room_name).child(user_id_or_name).setValue("true");
isTyping = true;
}
}
});

Categories