Android Dynamic Edit Texts - android

I have 85 settings items that I need to display on a view. I cannot use a RecyclerView or a ListView because EditTexts are horrible. Doing the way I am doing causes a huge slow down. I do not want to make these manually. Any help is appreciated.
Relevant code:
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
LinearLayout ll = (LinearLayout) view.findViewById(R.id.ssm_ll);
List<Category> AllCats = (List<Category>) getArguments().getSerializable("Category");
temp = new LinearLayout(getActivity());
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
new Thread(new Runnable() {
public void run() {
for (Category cg : AllCats) {
LinearLayout tv = (LinearLayout) inflater.inflate(R.layout.scoring_setting_template, null);
TextView Catwording = (TextView) tv.findViewById(R.id.sst_catwording);
Catwording.setText("" + cg.getCatWording());
temp.addView(tv);
}
}
}).run();
temp.addView(temp);
ll.addView(temp);
}

Too Long for Comment, Not Sure if it Works, Just a Suggestion to Try
I haven't tested this at all, but it was too long to suggest trying in a comment. If it doesn't work let me know and I will delete this as a possible answer (please keep from your negative votes again I am not certain of this as an answer).
Since an Adapter in a ListView is supposed to handle creating the next view that isn't seen, which allows smooth scrolling, you could possibly still manage this in a ListView (theoretically). You could programmatically set the id and handle the the next call like so within your Adapter's getView() :
editText.setId(position + 1); // + 1 so your id is never 0
if(position < getCount() - 1)
editText.setNextFocusDown(position + 2); // the id of the next edit text
else
editText.setImeOptions(EditorInfo.IME_ACTION.DONE);
Theoretically, your ListView will always have built the next item in the list's view unless it is the last item in the list (which you can then set the ime options to done), not 100% on that though. Again, I am not sure if this works but it is obviously too much for a comment.
while I am making a post
For the content of each EditText you could do something like
private SparseArray<String> mEditTextInputs = new SparseArrayt<>();
then in getView(), make position parameter final and try
editText.setText(mEditTextInputs.get(position);
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){
mEditTextInputs.put(position, s.toString());
}
}

This is not the best idea, but in order to do what you ask create a Layout and Populate a ScrollView with EditText so when you select next on keyboard it goes down one EditText:
Here is an example:
https://gist.github.com/lt-tibs1984/5d3e6a50f9d883026014
to go even further each time you do:
int count = 0;
for (String item : items) {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.list_item, null);
EditText editText = (EditText)view.findViewById(R.id.editTextDemo);
editText.setText(item);
// set a tag here to uniquely identify it later
editText.setTag(count);
mLinearLayout.addView(view);
count++;
}
Alternative loop:
for (int i = 0 ; i < 25; i++) {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.list_item, null);
EditText editText = (EditText)view.findViewById(R.id.editTextDemo);
editText.setText(items.get(i));
// set a tag here to uniquely identify it later
editText.setTag(i);
mLinearLayout.addView(view);
}

Related

Android InputType not honored

I have a listview with an EditText in each row. The EditText is supposed to collect numeric values so I tried to keep the alpha keyboard off and allow the user to only see the numeric keypad.
What happens, though, is that when the listview is populated and I click on any EditText in the list, the numeric keyboard appears - but is then quickly replaced by the full qwerty keyboard - and the user must switch back to numeric to input numbers.
I've tried various combinations programmatically, like so:
mPercent.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_NORMAL);
As well as multiple comnbinations of XML such as
android:inputType="phone"
or
android:digits="0123456789"
But, no matter the combination, they keyboard always rapidly switches back to qwerty and off the numeric keys.
I'm thinking it might be something with the TextWatcher. I use a textwatcher to indicate what has been typed. I remove it, add whatever text might be in that row's edittext and then add the textwatcher.
This is the guts of my custom adapter :
public View getView(final int position, View inView, ViewGroup parent) {
ViewHolder holder = null;
if (inView == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inView = inflater.inflate(mLayoutResource, null);
holder = new ViewHolder();
holder.mPercent = (EditText) inView.findViewById(R.id.percent);
holder.mMaterial = (TextView) inView.findViewById(R.id.name);
inView.setTag(holder);
} else {
holder = (ViewHolder) inView.getTag();
}
mMaterial.moveToPosition(position);
holder.mPercent.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_NORMAL);
// remove textwatcher on percentage
holder.mPercent.removeTextChangedListener(percentWatcher);
// insert the percentage for this row
final String material = mMaterial.getString(mMaterial.getColumnIndex(OptionsProvider.OPTIONS_DATA));
final EditText percent = holder.mPercent;
percent.setTag(material); // use material and position as keys into which of the many edittexts the textwatcher is watching
percent.setId(position);
holder.mMaterial.setText(material);
// persist any text the user may have typed in the comment box
if (percentages.containsKey(material)) {
percent.setText(percentages.get(material));
}
else {
percent.setText("");
}
// turn on textwatcher
percentWatcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// save this text and the position in which is resides.
// if the user scrolls before pressing send, only this position should
// contain the text
String text = percent.getText().toString().trim();
if (text.length() > 0) {
if ((position == percent.getId() &&
(material.equals( percent.getTag().toString())))) {
percentages.put(material, text);
Log.d(TAG, "Percentage inserted "+material+"="+text);
}
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
// force the EditText to stay with 3 digits (max of 100%)
#Override
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
int pct = Integer.parseInt(s.toString());
Log.d(TAG, " Material "+(String) percent.getTag()+ " = "+pct);
}
}
};
// add the textwatcher back to the edittext
holder.mPercent.addTextChangedListener(percentWatcher);
Anyone know if removing/adding a textwatcher corrupts the InputType? Is this a path I should explore to figure out why the keyboard always goes back to qwerty?
Might be that the ListView steals the focus. Try to add this your ListView
XML
android:descendantFocusability="afterDescendants"
Or in Java
listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

how to set value of edittext with same id in different inflated linearlayout views?

I have one main layout with one LinearLayout. In this LinearLayout I inflates multiple xml layouts that contain a form with multiple text fields(3 EditText) in it.
On first attempt I show only one form. There is button for adding more forms. Suppose If user clicks on "Add" button two times then user have three total forms. I successfully get all data of these three forms.
For doing this I am targeting the main layout "LinearLayout" and then counting its child. After counting its child I called child views of Main LinearLayout by its position and then get EditText data and save into a list. Then I moved this list to next page. Everything works fine till then. But if user comes back on previous page, all inflated layouts were gone. So, I count the size of list on resume and set the values what users wrote last time.
The problem is when I set the values of EditText according to its view position. Only last object(of list) value is shown in all inflated layouts. Means when for loop ends it sets last object value in all layouts. This is my method for setting values against a view:
private void addFormDataOnResume(LinearLayout viewForm,Traveller otherTraveller)
{
EditText dateOfBirthEt = (EditText)viewForm.findViewById(R.id.dateOfBirth);
dateOfBirthEt.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
showDatePickerDialog(dateOfBirthEt);
}
});
dateOfBirthEt.setText(otherTraveller.getOtherDateOfBirth());
EditText firstNameET = (EditText)viewForm.findViewById(R.id.firstName);
firstNameET.setText(otherTraveller.getOtherFirstName());
EditText lastNameEt = (EditText)viewForm.findViewById(R.id.lastName);
lastNameEt.setText(otherTraveller.getOtherLastName());
}
My loop code:
int otherTraSize = otherTravellersData.size();
//adultsForms is the main linear layout in which I am adding views
for(k=0; k < otherTraSize; k++)
{
addFormOnResume();//Function for adding form layout
int viewPos = adultsForms.getChildCount();
if(viewPos>0)
{
addFormDataOnResume(adultsForms.getChildAt(viewPos-1), otherTravellersData.get(k));
}
}
My FUnction for adding forms:
private void addFormOnResume()
{
LinearLayout viewForm = (LinearLayout)layoutInflater.inflate(R.layout.other_traveller_form, null );
adultsForms.addView(viewForm);
}
I debug my code, all data of list seems fine. Objects are in proper order with proper values.
Please help me why only last object value is set to all of the inflated forms.
Any help would be really appreciated......Thanks in Advance.
Finally I got the answer of my own question. By default when an activity goes in onPause mode. Android saves the EditText value against an id and when we resume it restore the last saved value of EditText. So, in my case it restoring last form values in all layout forms. The solution of my problem is to set android:saveEnabled="false" on the widget entry on the XML. I added this in all EditText. Android no longer saves my data and onResume I can set value of my form fields whatever I want to, by simply getting childView from specified position even if they have same Id.
Replace your loop code with this:
int otherTraSize = otherTravellersData.size();
//adultsForms is the main linear layout in which I am adding views
for(k=0; k < otherTraSize; k++)
{
addFormOnResume();//Function for adding form layout
}
int viewPos = adultsForms.getChildCount();
if(viewPos>0)
{
for(int x=0; x<viewPos; x++){
Log.d("current value",otherTravellersData.get(x).getOtherFirstName());
addFormDataOnResume(adultsForms.getChildAt(viewPos-1), otherTravellersData.get(x));}
}
Its my working code
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnAdd:
view = layoutInflater.inflate(R.layout.fragment_add_materials, null);
parentLinearLayout.addView(view);
arrayList.add(view);
edtMaterialName = (EditText) view.findViewById(R.id.edtinput_material1);
editTextCoast = (EditText) view.findViewById(R.id.editTextCoast1);
edtMaterialName.addTextChangedListener(getMyTextWatcher(edtMaterialName,arrayListMaterials.size()-1 ,"name"));
editTextCoast.addTextChangedListener(getMyTextWatcher(editTextCoast, arrayListMaterials.size()-1, "cost"));
break;
TextWatcher getMyTextWatcher(final EditText edtText, final int listPosition, String nameOrcost){
return new MyTextWatcher(edtText, listPosition, nameOrcost);
}
class MyTextWatcher implements TextWatcher{
int position;
EditText edtText;
String nameOrcost;
MaterialData data;
boolean flag;
int count;
public MyTextWatcher(EditText edtText1, int listPosition, String nameOrcost){
this.position = listPosition;
this.edtText=edtText1;
this.nameOrcost = nameOrcost;
data = arrayListMaterials.get(position);
}
#Override
public void afterTextChanged(Editable sEditable) {
try{
if(this.nameOrcost.equals("name") && edtText.getEditableText().toString().length()>0){
data.setMaterialName(edtText.getEditableText().toString());
}
if(this.nameOrcost.equals("cost") && edtText.getEditableText().toString().trim().length()>0){
String tempCost = edtText.getEditableText().toString().trim();
NumberFormat myFormatter = NumberFormat.getInstance();
Number number = myFormatter.parse(tempCost);
data.setMaterialprice(new BigDecimal(number.toString()).toString());
}
arrayListMaterials.set(position, data);
setTotalPrice(arrayListMaterials);
}catch (Exception e) {
e.printStackTrace();
}
if(this.nameOrcost.equals("cost") && edtText.getEditableText().toString().trim().length()>0){
Utilty.insertCommaIntoNumber(edtText, sEditable.toString());
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
try{
if(this.nameOrcost.equals("cost"))
data.setMaterialprice("0");
if(this.nameOrcost.equals("name"))
data.setMaterialName("");
arrayListMaterials.set(position, data);
}catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
}

Adding EditText fields on view when typing on a EditText

I want to create EditTextFields dynamically on depending the condition. Condition is that if I start typing on first EditTextField it will create one more EditTextField in the bottom and will create the third EditTextField when i start typing on second one. Similarly i want to delete the bottom text if there is no text in the upper EditTextField. Thanks.
Use a parent view, like a ScrollView that you know you can add a flexible about of content to. Then use a TextWatcher a/k/a a text change listener. You could then create a new text view which you would add to the ScrollView if text was typed into the EditText field.
For neatness I'd probably create a custom TextView class that housed this text change listener and replication check. Here's example of how you could add a TextView
//instance variable
private LinearLayout containerLayout;
private newTextViewCreated = false;
//initialize your conatinerLayout before you use it
//and create your first edit text field
public void onCreate(Bundle savedInstaceState){
containerLayout = (LinearLayout)findViewById(R.id.conatinerLinearLayout);
createEditText();
}
private void createEditText(){
EditText editText = new editText(this);
editText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(count > 0 && !newTextViewCreated){
createEditText();
newTextViewCreated = true;
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s) {
//TODO Auto-generated method stub
}
});
containerLayout.addView(editText);
}
I didn't test this out, I'm writing it now but here's what I'm thinking. Read the description of how a TextWatcher works so you understand the inner methods. You're going to have to play with the conditionals but what you're doing is listening for a change in the number of characters entered and then making a recursive call to create an additional view when chars are added to each text view. I use a boolean flag to show when a view has been created so we don't add one each time the char is changed. I moved outside the createEditText method based on your comment. If you made your own EditText class you could just add a method that would set/get the status of whether this TextView had spanwed another. To remove you would just add a delete condition that would remove the view from the linear layout.
User TextWatcher
Implement your Activity with TextWatcher and override method
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
Show / Hide them in your layout if you know the total amount of editText fields needed or add them programatically like so:
EditText myET = new EditText(MyActivity.this);
myET.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
LayoutContentView.addView(myET);
Then check:
if (myET.getText().toString().trim().equals(""))
{
//Don't Show
}else{
//SHOW
}
SO question could help:https://stackoverflow.com/a/6792359/350421
EditText toAdd = new EditText(this);
list.add(toAdd);

EditText in ListView hidden by keyboard when focused

I have a ListView containing rows with EditText's.
When I click on an EditText and it's not already focused it receives focus, the keyboard appears and the EditText is moved above the CandidateView (desired behaviour).
However when I make a key press, the EditText maintains focus and receives the input but moves down and is obscured by the keyboard (the previous movement is reversed).
When I click on the EditText when it is already selected without the keyboard shown, the keyboard pops up but the EditText is not moved to the right position (above the CandidateView). It still receives the input.
I add a header view containing EditText's and there everything works correctly.
This is the code of my ArrayAdapter where the row view is created:
View view = inflater.inflate(R.layout.row_profile_entry_text, null);
final String question = getItem(position);
TextView textViewQuestion = (TextView) view.findViewById(R.id.rpeq_TextViewQuestion);
textViewQuestion.setText(question);
final EditText editTextAnswer = (EditText) view.findViewById(R.id.rpeq_EditTextAnswer);
editTextAnswer.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
mAnswers.put(question, s.toString());
}
});
if (mAnswers.containsKey(question)) {
editTextAnswer.setText(mAnswers.get(question));
}
return view;
I would also like to emphasize that I already added
android:windowSoftInputMode="adjustPan" to the Manifest and android:descendantFocusability="beforeDescendants" to the ListView as most of the answers to other questions suggest.
Without adjustPan the EditText is not able to receive focus at all but it does not solve the issue entirely.
Does someone have an idea what I am doing wrong?
Try this:
<activity name="YourActivity"
android:windowSoftInputMode="stateVisible|adjustResize|adjustPan">
</activity>
in the manifest file.
Most probably, adjustResize must work, if you are using a ScrollView.
after many hours spent on this problem this is my solution (for Android < 4.2):
1) Manifest => android:windowSoftInputMode="adjustPan"
2) Activity=> create OnTouchListner and pass to Adapter
private OnTouchListener exampleOnTouchListener = new OnTouchListener() {
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEvent.ACTION_UP == event.getAction()) {
int position = (Integer) v.getTag();
myListView.setSelection(position);
}
return false;
}
};
3) Adapter
if (exampleOnTouchListener!= null) {
myEditText.setTag(position);
myEditText.setOnTouchListener(exampleOnTouchListener);
// if last element set padding bottom for spacing
if (position == items.size() - 1) {
LinearLayout myLinearLayout = (LinearLayout) convertView
.findViewById(R.id.ticketcontolProposedRealvalueLinearLayout);
myLinearLayout.setPadding(0, 0, 0,SET_PADDING_BOTTOM);
}
}

Android ListView scrollTo

I have a LinearLayout that contains some other views and among those a ListView.
This view is loaded from another one by clicking a button.
This button somehow specify what element in the ListView needs to be the first visible one in the list. The elements that populates the list are retrieved via HTTP from an external server.
The problem is that I can get the Nth element to be the first in the list.
Please note, I do not want to move it form it current position to a new one, I want the list to scroll.
I have tried with setSelected() and scrollTo(x,y) and scrollBy(x,y) but with no luck.
I have also gave a try to this pice of code, as ugly as it is, but I just wanted to try f it was working:
ListView categoryList = (ListView)findViewById(R.id.category_list);
categoryList.post(new Runnable() {
#Override
public void run() {
Log.d(this.getClass().getName(), "CategoryActivity.scrollToIndex: " + CategoryActivity.scrollToIndex);
if(CategoryActivity.scrollToIndex>0){
ListView categoryList = (ListView)findViewById(R.id.category_list);
categoryList.setScrollContainer(true);
categoryList.scrollTo(4, CategoryActivity.scrollToIndex * 50);
categoryList.requestLayout();
}
}
});
And this gave me some success, but the ListView was then behaving crazy in a way I am not even able to describe....
Any idea?
Try to add it to the message queue
categoryList.post(new Runnable() {
public void run() {
categoryList.scrollTo(4, CategoryActivity.scrollToIndex * 50);
}
});
It worked for me in a ScrollView (check this answer).
i made functions that could be useful for others for listview scrolling, they work for me in every android version, emulator and device, here itemheight is the fixed height of view in the listview.
int itemheight=60;
public void scrollToY(int position)
{
int item=(int)Math.floor(position/itemheight);
int scroll=(int) ((item*itemheight)-position);
this.setSelectionFromTop(item, scroll);// Important
}
public void scrollByY(int position)
{
position+=getListScrollY();
int item=(int)Math.floor(position/itemheight);
int scroll=(int) ((item*itemheight)-position);
this.setSelectionFromTop(item, scroll);// Important
}
public int getListScrollY()
{
try{
//int tempscroll=this.getFirstVisiblePosition()*itemheight;// Important
View v=this.getChildAt(0);
int tempscroll=(this.getFirstVisiblePosition()*itemheight)-v.getTop();// Important
return tempscroll;
}catch(Exception e){}
return 0;
}

Categories

Resources