Currently I use a RecyclerView to represent a dynamically configuration list form.
Every configuration item (entry at RecyclerView list) contains one EditText item.
To avoid wrong user input (some fields allow only integer, others only one digit after comma), I've implemented two different TextWatcher-filters which correct illegal input ("DecimalFilterDigitsAfterComma" and "DecimalFilterInteger").
My RecyclerView has 16 configuration items in total, but can only display maximum 8 at one time.
My problem is that the TextWatchers are assigned to specific Items (Integers and Decimal-Point TextEdit). But when I'm scrolling a bit, they change their order, so that Decimal- and Integer-Filters get swapped.
The TextWatcher items will be created inside the ConfigurationAdapter which is a RecyclerView.Adapter. I've event managed that the TextWatcher is only created once for each entry by using the mListConfigInit which is a boolean flag list for the items.
ConfigurationAdapter.java:
public class ConfigurationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
/*
...
*/
private List<ConfigItem> mConfiguration = new ArrayList<>();
// make sure that DecimalFilter is only created once for each item
private List<Boolean> mListConfigInit = new ArrayList<>();
public ConfigurationAdapter() {
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.listitem_configuration,
parent,
false);
final ConfigurationViewHolder vh = new ConfigurationViewHolder(v);
/*
...
*/
return vh;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final ConfigurationViewHolder vh = (ConfigurationViewHolder) holder;
ConfigItem config = mConfiguration.get(position);
if(config.ShowValueAsFloat()) {
vh.SetTextWatcherType(ConfigurationViewHolder.TextWatcherType.type_FloatActive);
} else {
vh.SetTextWatcherType(ConfigurationViewHolder.TextWatcherType.type_IntActive);
}
// set name and unit
vh.mName.setText(config.mName);
vh.mUnit.setText(config.mUnit);
/*
...
*/
}
#Override
public int getItemCount() {
return mConfiguration.size();
}
public void addConfigItem(ConfigItem item) {
mConfiguration.add(item);
mListConfigInit.add(new Boolean(false));
notifyItemInserted(mConfiguration.size() - 1);
//notifyDataSetChanged();
}
/*
...
*/
}
ConfigurationViewHolder.java (changed according to pskink-comments):
public final class ConfigurationViewHolder extends RecyclerView.ViewHolder implements TextWatcher {
public TextView mName;
public CheckBox mCheckbox;
public SeekBar mSeekbar;
public EditText mValueEditText;
public TextView mUnit;
private List<TextWatcher> mListTextWatchers = new ArrayList<>();
public enum TextWatcherType {
type_FloatActive(0),
type_IntActive(1);
private int mValue;
TextWatcherType(int value) {
mValue = value;
}
int val() { return mValue; }
}
private TextWatcherType mTextWatcherType = TextWatcherType.type_FloatActive;
public ConfigurationViewHolder(View itemView) {
super(itemView);
mName = (TextView) itemView.findViewById(R.id.textView_configuration_name);
mValueEditText = (EditText) itemView.findViewById(R.id.editText_configuration_value);
mUnit = (TextView) itemView.findViewById(R.id.textView_configuration_unit);
mCheckbox = (CheckBox) itemView.findViewById(R.id.checkbox_configuration);
mSeekbar = (SeekBar) itemView.findViewById(R.id.seekBar_configuration);
mListTextWatchers.add(0, new DecimalFilterDigitsAfterComma(mValueEditText, 1));
mListTextWatchers.add(1, new DecimalFilterInteger(mValueEditText));
mValueEditText.addTextChangedListener(this);
}
public void SetTextWatcherType(TextWatcherType textWatcherType) {
mTextWatcherType = textWatcherType;
}
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
#Override
public void afterTextChanged(Editable editable) {
mListTextWatchers.get(mTextWatcherType.val()).afterTextChanged(editable);
}
}
DecimalFilterInteger.java
public class DecimalFilterInteger implements TextWatcher {
private final static String TAG = ConfigurationAdapter.class.getSimpleName();
private final EditText mEditText;
private String mLastTextValue = new String("");
public DecimalFilterInteger(EditText editText) {
this.mEditText = editText;
}
#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 synchronized void afterTextChanged(final Editable text) {
String strInput = text.toString().trim();
if(strInput.isEmpty()) {
return;
}
if(strInput.equals(mLastTextValue)) { // return when same value as last time to avoid endless loop
return;
}
if ((strInput.charAt(0) == '.')) { // handle dot at beginning
strInput = "";
}
if(strInput.contains(".")){ // cut trailing comma
String numberBeforeDecimal = strInput.split("\\.")[0];
strInput = numberBeforeDecimal;
}
mEditText.removeTextChangedListener(this);
mEditText.getText().clear(); // do not use setText here to avoid changing the keyboard
mEditText.append(strInput); // back to default (e. g. from 123-mode to abc-mode),
// see: http://stackoverflow.com/questions/26365808/edittext-settext-changes-the-keyboard-type-to-default-from-123-to-abc
mLastTextValue = mEditText.getText().toString();
mEditText.setSelection(mEditText.getText().toString().trim().length());
mEditText.addTextChangedListener(this);
}
}
Many thanks in advance for your help!
The cause of the swap/switching behaviour of the two different TextWatcher-implementations inside the RecyclerView was that I called removeTextChangedListenerand addTextChangedListenerinside their afterTextChanged-methods to avoid retriggering of the afterTextChanged-method.
The best way to avoid retriggering is a simple check if the text changed since the last call:
public class DecimalFilterInteger implements TextWatcher {
private final static String TAG = ConfigurationAdapter.class.getSimpleName();
private final EditText mEditText;
private String mLastTextValue = new String("");
// ...
#Override
public synchronized void afterTextChanged(final Editable text) {
String strInput = text.toString().trim();
if(strInput.isEmpty()) {
return;
}
if(strInput.equals(mLastTextValue)) { // return when same value as last time to avoid endless loop
return;
}
if ((strInput.charAt(0) == '.')) { // handle dot at beginning
strInput = "";
}
if(strInput.contains(".")){ // cut trailing comma
String numberBeforeDecimal = strInput.split("\\.")[0];
strInput = numberBeforeDecimal;
}
//mEditText.removeTextChangedListener(this); // CAUSE OF SWAP-ERROR !!!
mEditText.getText().clear(); // do not use setText here to avoid changing the keyboard
mEditText.append(strInput); // back to default (e. g. from 123-mode to abc-mode),
// see: http://stackoverflow.com/questions/26365808/edittext-settext-changes-the-keyboard-type-to-default-from-123-to-abc
mLastTextValue = mEditText.getText().toString();
mEditText.setSelection(mEditText.getText().toString().trim().length());
//mEditText.addTextChangedListener(this); // CAUSE OF SWAP-ERROR !!!
}
}
Related
EditText input value erase after scrolling down and scrolling up.
I followed many tutorials but nothing worked for me, I tried to implement Textwatcher but I can't perfectly implement it.
Someone please help, I'm stuck with this problem. Please give me a solution if it had multiple edittext too.
here is my adapter code.
public class ClassTestMarkAdapter extends RecyclerView.Adapter<ClassTestMarkAdapter.NviewHolder> {
private Context mCtx;
private List<ClassTestMarkModel> marklist;
public ClassTestMarkAdapter(Context mCtx, List<ClassTestMarkModel> marklist) {
this.mCtx = mCtx;
this.marklist = marklist;
}
#NonNull
#Override
public NviewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int position) {
LayoutInflater inflater =LayoutInflater.from(mCtx);
View v = inflater.inflate(R.layout.class_test_mark_list,null);
NviewHolder holder =new NviewHolder(v,new MyCustomEditTextListener());
return holder;
}
#Override
public void onBindViewHolder(#NonNull final NviewHolder nviewHolder, int position) {
ClassTestMarkModel markModel =marklist.get(position);
nviewHolder.myCustomEditTextListener.updatePosition(nviewHolder.getAdapterPosition());
nviewHolder.wrText.setText(marklist[nviewHolder.getAdapterPosition()]);
nviewHolder.stname.setText(markModel.getUserName());
nviewHolder.stroll.setText(markModel.getRoll());
nviewHolder.wrText.setText(markModel.getMarks());
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mCtx);
Long instituteID = prefs.getLong("InstituteID",0);
final String inssid=String.valueOf(instituteID);
final String subId = prefs.getString("subId", "");
final String examids = prefs.getString("examidforct", "");
final String sessionId = prefs.getString("sesId", "");
final String cTMarkID=markModel.getcTMarkID();
final String insCTID=markModel.getInsCTID();
final String userID=markModel.getUserID();
nviewHolder.btnMark.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
RequestQueue myRequestQueue = Volley.newRequestQueue(mCtx);
String url = mCtx.getResources().getString(R.string.baseUrlLocal)+"setExamCTMarks";
final String xNon=nviewHolder.wrText.getText().toString();
Double wrsum= Double.valueOf(xNon);
if (wrsum>0){
nviewHolder.btnMark.setText("Success!");
nviewHolder.btnMark.setBackgroundColor(Color.parseColor("#009000"));
}
StringRequest myStringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Toast.makeText(mCtx,"Success! Data Posted Sucessfully",Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() { //Create an error listener to handle errors appropriately.
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(mCtx,"Error: Something Wrong...",Toast.LENGTH_SHORT).show();
}
}) {
protected Map<String, String> getParams() {
Map<String, String> MyData = new HashMap<String, String>();
MyData.put("CTMarkID", cTMarkID);
MyData.put("InsCTID", insCTID);
MyData.put("UserID",userID);
MyData.put("SessionID", sessionId);
MyData.put("SubjectID", subId);
MyData.put("ExamID", examids);
MyData.put("ObtainMarks",xNon);
MyData.put("InstituteID",inssid);
MyData.put("IsAbsent", "");
MyData.put("LoggedUserID", "123");
MyData.put("IP", "123");
return MyData;
}
};
myRequestQueue.add(myStringRequest);
}
});
}
#Override
public int getItemCount() {
return marklist.size();
}
class NviewHolder extends RecyclerView.ViewHolder{
TextView stname, stroll;
LinearLayout parentLayout;
Button btnMark;
EditText wrText;
//String wrMark;
public MyCustomEditTextListener myCustomEditTextListener;
public NviewHolder(#NonNull View itemView, MyCustomEditTextListener myCustomEditTextListener) {
super(itemView);
stname =itemView.findViewById(R.id.clsmarkName);
stroll =itemView.findViewById(R.id.clsmkRoll);
parentLayout = itemView.findViewById(R.id.ctMarkList);
btnMark =itemView.findViewById(R.id.clsmarkBtn);
this.wrText = itemView.findViewById(R.id.editText);
this.myCustomEditTextListener = myCustomEditTextListener;
this.wrText.addTextChangedListener(myCustomEditTextListener);
}
}
private class MyCustomEditTextListener implements TextWatcher {
private int position;
public void updatePosition(int position) {
this.position = 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) {
marklist[position] = s.toString();
}
#Override
public void afterTextChanged(Editable s) {
}
}
}
Update your list item on text change using text watcher after setText to edit text.
Or Alternatively, For best practices use two way data binding to overcome this issue.
Friends , I have an edittext which is acting like a searchview.On text change,it is fetching data and storing in filterdNames but it is not updating the recyclerview.Kindly help, i am new to andriod.
Here is my recyclerview adapter code-
public class MyCategoryAdaptercheckbox extends RecyclerView.Adapter<MyCategoryAdaptercheckbox.ViewHolder> {
List<GetMyCategoryAdapter> getMyCategoryAdapter;
Context context;
List<String> category_name;
GetMyCategoryAdapter getMyCategoryAdapter1;
public MyCategoryAdaptercheckbox(List<GetMyCategoryAdapter> getMyCategoryAdapter, Context context, List<String> category_name) {
this.getMyCategoryAdapter = getMyCategoryAdapter;
this.context = context;
this.category_name = category_name;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int i) {
if (viewHolder instanceof ViewHolder){
}
getMyCategoryAdapter1 = getMyCategoryAdapter.get(i);
((ViewHolder) viewHolder).tv_categorytitle.setText(getMyCategoryAdapter1.getC_name());
((ViewHolder) viewHolder).tv_categoryid.setText(getMyCategoryAdapter1.getC_id());
((ViewHolder) viewHolder).gt= getMyCategoryAdapter1;
}
public void filterList(ArrayList<String> filterdNames) {
this.category_name = filterdNames;
notifyDataSetChanged();
}
}
Here is my GetMyCategoryAdapter class code -
public class GetMyCategoryAdapter {
String c_name,c_id;
public String getC_name() {
return c_name;
}
public void setC_name(String c_name) {
this.c_name = c_name;
}
public String getC_id() {
return c_id;
}
public void setC_id(String c_id) {
this.c_id = c_id;
}
}
And here is the fragment code -
searchView.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
//after the change calling the method and passing the search input
filter(editable.toString());
}
});
private void filter(String text) {
//new array list that will hold the filtered data
ArrayList<String> filterdNames = new ArrayList<>();
//looping through existing elements
for (String s : category_name) {
//if the existing elements contains the search input
if (s.toLowerCase().contains(text.toLowerCase())) {
//adding the element to filtered list
filterdNames.add(s);
}
}
//calling a method of the adapter class and passing the filtered list
((MyCategoryAdaptercheckbox) MyAdapter).filterList(filterdNames);
}
The problem is in filterList method:
you update category_name, but not getMyCategoryAdapter (which is used in onBindViewHolder). Try change getMyCategoryAdapter as well before notifyDataSetChanged
How can I retrieve the value from all EditTexts created by the RecyclerView in MainActivity?
In my RecyclerView Adapter I'm extending my inner class:
public class MyPersonalAdapter extends RecyclerView.Adapter<MyPersonalAdapter.MyPersonalViewHolder>
I'm getting a reference to the EditText in that inner class:
class MyPersonalViewHolder extends RecyclerView.ViewHolder {
TextView numberTextView;
EditText nameEditText;
public MyPersonalViewHolder(View itemView) {
super(itemView);
numberTextView = (TextView) itemView.findViewById(R.id.tv_number);
nameEditText = (EditText) itemView.findViewById(R.id.et_name);
}
}
and in my MainActivity I want to use:
for (int i = 0; i < count; i++) {
String name = "Somehow get that name";
cv.put(MyContract.MyEntry.COLUMN_NAME, "name");
}
Got it working, here is the edited code:
mAdapter = new MyClassAdapter(this, mDataset.size);
mRecyclerView.setAdapter(mAdapter);
mRecyclerview.setItemViewCacheSize(mDataset.size());
List<ContentValues> list = new ArrayList<>();
for (int i = 0; i < mDataset.size(); i++) {
View view = recyclerView.getChildAt(i);
EditText nameEditText = (EditText) view.findViewById(R.id.et_name);
String name = nameEditText.getText().toString();
ContentValues cv = new ContentValues();
cv.put(MyContract.MyEntry.COLUMN_NAME, name);
list.add(cv)
}
// I encapsulated this in a try catch
for (ContentValues c:list) {
mDb.insert(MyClassContract.MyClassEntry.TABLE_NAME, null, c);
}
try this:
for(int i=0;i<adapter.getItemCount();i++){
MyPersonalViewHolder viewHolder= (MyPersonalViewHolder )
mRecyclerView.findViewHolderForAdapterPosition(i);
EditText editText=viewHolder.nameEditText;
}
Implement a addTextChangedListener inside bindview method in the recyclerview adapter.
everytime the edittext text is modified in any cell modify the arraylist string at that position.
And later when you need the whole arraylist, just send it back from the adapter class via any public getmethod.
This should be enough.
I created a getData function inside my Adapter class.
public String getData()
{
String s;
s=txt1.getText().toString();
return s;
}
Then in my MainActivity
public void onSave(View view) {
String[] s=new String[length];
for(int i=0;i<ad.getItemCount();i++)
{
s[i]=ad.getData().toString();
}
}
By this, you can save edit text entries in the array.
//So the other day I spend full day to get data(list of edittext) from recyclerview to activity when i press
button in activity
//perform onclick of button
Here is the code in adapter,Did't work with textchange listener..So i had to used textchange listener and setOnfoucusChange(100% working)
holder.mComment.setOnFocusChangeListener(new
View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
/* When focus is lost check that the text field
* has valid values.
*/
if (!hasFocus) {
String data=holder.mComment.getText().toString();
commentList[position]=data;
}
if(position==mList.size()-1){
holder.mComment.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence s, int i, int i1, int i2) {
commentList[position]=s.toString();
}
#Override
public void afterTextChanged(Editable editable) {
}
});
}
}
});
Intent intent = new Intent("mrn_intent");
Bundle args = new Bundle();
args.putSerializable("comment_list",(Serializable)commentList);
args.putSerializable("rating_list", (Serializable) mRatingList);
intent.putExtra("BUNDLE_COMMENT",args);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
And in activity write the following code
Bundle args2 = intent.getBundleExtra("BUNDLE_COMMENT");
if(args2!=null){
list = (String[]) args2.getSerializable("comment_list");
Log.d(TAG, "onReceive: list+++=>>>>>>"+list);
}
This worked for me:
mySetEnabled is a method I implemented within my viewHolder.
if(mRecView!=null) {
int size=mRecView.getChildCount();
for (int i = 0; i < size; i++) {
myAdapter.myViewHolder wordView = (myAdapter.myViewHolder)mRecView.findViewHolderForLayoutPosition(i);
if(wordView!=null)
wordView.mySetEnabled(state);
}
}
Try this way,
class MyPersonalViewHolder extends RecyclerView.ViewHolder {
TextView numberTextView;
EditText nameEditText;
public MyPersonalViewHolder(View itemView) {
super(itemView);
numberTextView = (TextView) itemView.findViewById(R.id.tv_number);
nameEditText = (EditText) itemView.findViewById(R.id.et_name);
nameEditText.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) {
values.add(getAdapterPosition(),s.toString());
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
}
Also, define a function
public String getValue(int position){
return values.get(position);
}
Now getValue can call from MainActivity.
OK. I had the same problem, but my solution was different and simpler. Basically, I'd a list of objects, and I was using the edittext to update their values. So, to do it correctly, instead of using position, I used a for loop and if I reach the object that have the same name of my textview, I break the loop and update using i as my index. You can see the code that I have been using in my adapter bellow:
int i;
for(i = 0; i<list.size(); i++){
if(list.get(i).getName().equals(holder.name.getText())){
break;
}
}
Commodity updated = list.get(i);
updated.setValor(Float.parseFloat(s.toString())); // recovering value of my edit text
list.set(i, updated);
atualizado[i] = Float.parseFloat(s.toString());
I am trying to create an edit text with a text watcher that displays the phone number correctly, to start out I am just testing it with a US number.
If I go to this site
http://libphonenumber.appspot.com/
And type in US and the number 9188143287 the results look perfect however when I implement the library as they say I am getting different results
Here is my fragment
ublic class PhoneNumberFragment extends Fragment{
private TextView next;
private EditText phoneNumber;
private PhoneNumberUtil phoneUtil;
private AsYouTypeFormatter formatter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_phone_number, container, false);
phoneUtil = PhoneNumberUtil.getInstance();
formatter = phoneUtil.getAsYouTypeFormatter("US");
init(v);
return v;
}
private void init(View v){
next = (TextView) v.findViewById(R.id.next);
phoneNumber = (EditText) v.findViewById(R.id.phoneNumber);
phoneNumber.addTextChangedListener(new PhoneNumberTextWatcher());
}
private void turnOnNext(){
next.setBackgroundResource(R.color.warningRed);
}
private class PhoneNumberTextWatcher implements TextWatcher{
private boolean isFormatting = false;
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO: implement your code
}
#Override
public void afterTextChanged(Editable s) {
// TODO: implement your code
}
#Override
public synchronized void onTextChanged(CharSequence s, int start, int before,
int count) {
if(before > count) {
return;
}
if(!isFormatting) {
isFormatting = true;
try {
formatter.clear();
for(int i=0; i<s.length();i++) {
phoneNumber.setText(formatter.inputDigit(s.charAt(i)));
phoneNumber.setSelection(phoneNumber.getText().length());
}
} catch (Exception e) {}
isFormatting = false;
}
}
}
}
My results are correct up to 7 digits, but then on the 8th digit the brackets are supposed to appear around the first 3 and they do not.
Thanks for any help!
So, I have an activity with a TextView and a ListView with a custom BaseAdapter. This activity looks like this:
As you can see, every item of the list is a custom layout and the basic idea is: every time the numeric EditText within it changes, the "total" TextView from the activity (which is the sum of the prices of every product) must be updated as well.
I suppose it must somehow be done from the Adapter class, but I don't know how to do it.
My Activity file looks like this (it gets products data from server via "GetCollectionProducts" AsyncTask, where I set the adapter):
public class ProductAisleActivity extends AppCompatActivity implements View.OnClickListener{
ListView productList;
Button participate;
ImageButton search;
EditText searchET;
TextView productsTotal;
Product[] colProducts;
RelativeLayout collectionHeader;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_product_aisle);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
/* ...
Irrelevant code to this question
*/
productsTotal = (TextView) findViewById(R.id.products_aisle_total);
productsTotal.setText(
getResources().getString(
R.string.productsTotal,
String.valueOf(0.00)
)
);
productList = (ListView) findViewById(R.id.products_aisle_list);
new GetCollectionProducts().execute();
}
private class GetCollectionProducts extends AsyncTask<Void,Void,JSONArray>{
#Override
protected JSONArray doInBackground(Void... voids) {
/* Irrelevant code to this question */
}
#Override
protected void onPostExecute(JSONArray jsonArray) {
/* Irrelevant code to this question */
productList.setAdapter(
new CollectionProductsAdapter(
ProductAisleActivity.this,
colProducts
)
);
}
}
And my Adapter file looks as follows:
public class CollectionProductsAdapter extends BaseAdapter {
Context context;
ProductAisleActivity.Product[] data;
private static LayoutInflater inflater = null;
public CollectionProductsAdapter(Context context, ProductAisleActivity.Product[] data) {
this.context = context;
this.data = data;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return data.length;
}
#Override
public Object getItem(int i) {
return data[i];
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
View v = view;
if (v == null) {
v = inflater.inflate(R.layout.product_row_layout, null);
}
ProductAisleActivity.Product product = data[i];
/* ...
Irrelevant code to this question
*/
EditText productQuantity = (EditText) v.findViewById(R.id.productQuantity);
productQuantity.setText("0");
return v;
}
}
I'm stuck at this point, any help will be appreciated.
First you need to listen for any changes in the EditText so you can handle things dynamically without explicitly using something like a submit button. You can do this with a TextWatcher.
productQuanity.addTextChangedListener(new TextWatcher() {
private double originalCost = 0.0;
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Before we change the text, set the originalCost
// so we can know what the change is after the edit
originalCost = getCost(s.toString());
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// You don't need to utilize this method
}
#Override
public void afterTextChanged(Editable s) {
// After the change has taken place in the text,
// get the new cost and calculate the difference
double newCost = getCost(s.toString());
double changeInCost = newCost - originalCost;
}
private double getCost(String input){
String count = input.toString();
if(TextUtils.isEmpty(count))
return 0.0;
else
return (double) Integer.parseInt(count) * product.getPrice();
}
});
Now that we have the change in cost, what do we do with it? We need to notify the activity that we have a change. We can do that with an observer, which is fine, but for fun let's use an interface to implement a listener.
Modify your adapter class
public class CollectionProductsAdapter extends BaseAdapter {
public interface CostChangedListener{
void onCostChanged(double change);
}
Context context;
ProductAisleActivity.Product[] data;
private LayoutInflater inflater = null; // THIS SHOULDN'T BE STATIC
CostChangedListener listener;
public CollectionProductsAdapter(Context context, ProductAisleActivity.Product[] data, CostChangedListener listener) {
this.context = context;
this.data = data;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.listener = listener;
}
// The rest of your code
}
Now when we update the cost in our TextWatcher we can call
if(listener != null)
listener.onCostChanged(changeInCost);
Last, to make sure we utilize this correctly, we will need to pass a listener in our CollectionProductsAdapter constructor
productList.setAdapter(new CollectionProductsAdapter(
ProductAisleActivity.this, colProducts,
new CostChangeListener(){
#Override
public void onCostChanged(double change){
double currentTotal = Double.valueOf(productTotal.getText());
double newTotal = currentTotal + change;
productTotal.setText(String.valueOf(newTotal));
}));
Obviously you may need to tweak some of this to get it to match perfectly, and I haven't tested it so some things might be off a bit, but this should get you going in the right direction. If you have any issue feel free to comment and I will try to help you through it.
Notes
Do not keep a static reference like you were with your layout inflater
It is worth taking a look at the RecyclerView or at least the ViewHolder pattern with an Adapter
You want to add a textChangedListener for changing item values as user changes values in EditText.
You can use TextChangedListener here:
EditText myEditTextField = new EditText(this);
myEditTextField.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) {
}
});
You can perform tasks according to your need. It has 3 methods:
1.beforeTextChanged
2.onTextChanged
3.afterTextChanged
So you can get your task done by the help of "afterTextChanged". You have to simply call your method of calculating price for no. of items when user enters a particular number.And it will show you the price as you want.
Hope this help!