Ungureanu Liviu
Ungureanu Liviu

Reputation: 4124

What is the best way to implement a large form layout in Android?

In my application I have to generate a big form with lot of elements (an element is usually and label + attribute (edditext, spinner, checkbox,...)).

When a form contains more elements (>20), the application is start lagging, opening the keyboard by example take around 1-2sec or the scrolling is slow.

What I tried

  1. At the moment each element is inflated from xml (a LinearLayout with a TextView and another component) and added to form layout. I tried to "re-use" (practically re-add) an element but I got and exception saying that the View already has a parent which make sense since I was already added to my form layout.

  2. I tried to add all the elements in a ListView to make sure that the views are re-used. It is working but not verry good: the problem in this case is that if I have an EditText, the user enter some text and scroll to bottom of the list, I couldn't find a way to save the text from EditText so I will be added back in EditText when the element will be visible again in ListView (the user scroll back to my element).

Question

Do you know any way to use lot of UI components but in same time to keep a good app performance? Do you think it is possible to get the text from an EditText just before the user start the scroll?

Thank you.

Upvotes: 1

Views: 1978

Answers (1)

Phil
Phil

Reputation: 36289

Sounds like you have some sort of preference screen. If that is the case, consider using PreferenceActivity. If that will not work, what about a ListView, which has built-in methods for reusing layout? If neither of these options will work, you can create your own ViewAdapter, which works in very much the same way as a ListView. Simply create a class - such as MyViewAdapter. It should take in arguments to help configure what it will look like - such as the label text and what the other element is:

public class MyViewAdapter {

    public static enum InputType {
        editor, spinner, checkbox
    };

    private CharSequence labelText;
    private InputType input;

    public MyViewAdapter(CharSequence text, InputType inputType) {
        this.labelText = text;
        this.input = inputType;
    }

}

As for knowing what text is inside your EditText - just use TextWatcher to listen for changes to the text. Although you can get before and after scroll callbacks, it requires hacking the built-in ScrollView. This example is added into the below code.

Next, add a method called getView(Context) as follows:

public View getView(Context context) {
    //here is where you inflate your view. For example:
    LinearLayout ll = new LinearLayout(context);
    ll.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
    ll.setOrientation(LinearLayout.VERTICAL);

    TextView tv = new TextView(context);
    tv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
    tv.setText(labelText);
    ll.addView(tv);

    switch (input) {
        case (InputType.spinner) : {
            //TODO (see editor example)
            break;
        }
        case (InputType.checkbox) : {
            //TODO (see editor example)
            break;
        }
        default ://default to editor
        case (InputType.editor) : {
            EditText et = new EditText(context);
            et.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
            et.addTextChangedListener(new TextWatcher() {
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    // TODO Auto-generated method stub
                }

                @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
                }
            });
            ll.addView(et);
            break;
        }
    }

    return ll;
}

Finally, to use this ViewAdapter, create them in your main activity:

List<MyViewAdapter> adapters = new ArrayList<MyViewAdapter>();//easy way to manage these.

//for each adapter, do something like:
adapters.add(new MyViewAdapter("myText:", InputType.editor));

Then, to inflate the views, do:

//Let's say your Main View is a LinearLayout called myView.
for (MyViewAdapter adapter : adapters) {
    myView.addView(adapter.getView(context));
}

Upvotes: 3

Related Questions