Re-Ordering list view in Android 2.2.

Today, we are going to see how to achieve the ordering of data in a list in the application at runtime. There was no official support for drag & drop until Android 3.0, after which a drag & drop framework have been added in the Android SDK. We needed to re-arrange some textual data in one of our projects based on user’s priority. Ordering data based on ascending or descending order is possible through code but how do we achieve the same based on user’s input. So, we came up with this idea of generating lists and on clicking the list item, the arrows to move the item up or down get activated.

For this article, the list we’ve used is not the default list from android toolkit. We’ll be using a generated list containing RelativeLayouts. So lets get started.

In the application’s main layout file, we’ve added a scrollview with a linear layout child and have named it “llReordering”. We are generating the list of RelativeLayout objects and to identify the clicked item and the items above and below it, we need to memorize the relative layouts in our application.

private ArrayList<RelativeLayout> rlayoutList = new ArrayList<RelativeLayout>();

private ArrayList<String> numbers = new ArrayList<String>();

The numbers arraylist will be containing our string literals to be re-arranged at runtime. After setContentView in the onCreate() method of our application’s default activity, add this block:

numbers.add(“One”);

numbers.add(“Four”);

numbers.add(“Three”);

numbers.add(“Six”);

numbers.add(“Two”);

numbers.add(“Five”);

numbers.add(“Seven”);

numbers.add(“Nine”);

numbers.add(“Ten”);

numbers.add(“Eight”);

llReordering = (LinearLayout)findViewById(R.id.llReordering);

generateNumbers();

The generateNumbers() method adds RelativeLayouts with a TextView attached to it for a total of 10 objects, according to the size of our numbers list.

public void generateNumbers() {

       if (llReordering!=null && llReordering.getChildCount()>0) {

              llReordering.removeAllViews();

       }

       max = numbers.size();

       ListIterator<String> liNumbers = numbers.listIterator();

       int i=1;

       while(liNumbers.hasNext()) {

              String number = liNumbers.next();

              generateUIForNumbers(i, number);

              i++;

       }

}

At the beginning of this method, we are checking if our linear layout “llReordering” has any child before and if it has we removeAllViews from it. Otherwise, all the objects will get appended to the linear layout continuously which we don’t want. Then, we are iterating the numbers list and for each string literal, we are calling the generateUIForNumbers() method passing the index and the actual string literal.

The method looks like:

public void generateUIForNumbers(int index, String number) {

       RelativeLayout rlCodes = new RelativeLayout(getApplicationContext());

       RelativeLayout.LayoutParams llParams = new RelativeLayout.LayoutParams(

              LayoutParams.FILL_PARENT, 70);

       rlCodes.setLayoutParams(llParams);

       rlCodes.setGravity(Gravity.CENTER_VERTICAL);

       rlCodes.setTag(number);

             

       TextView tvCodesDesc = new TextView(getApplicationContext());

       tvCodesDesc.setLayoutParams(llParams);

       tvCodesDesc.setGravity(Gravity.LEFT);

       tvCodesDesc.setPadding(8, 5, 0, 1);

       tvCodesDesc.setTextColor(Color.BLACK);

       tvCodesDesc.setTextSize(16);

       tvCodesDesc.setEllipsize(TruncateAt.END);

       tvCodesDesc.setSingleLine();

       tvCodesDesc.setText(number);

       rlCodes.addView(tvCodesDesc);

             

       rlCodes.setOnClickListener(new OnClickListener() {

                    

              @Override

              public void onClick(View v) {

                     RelativeLayout rlCode = (RelativeLayout)v;

                     String myString = (String)rlCode.getTag();

                     for (int r=0; r<rlayoutList.size(); r++) {

                           RelativeLayout tmpRl = rlayoutList.get(r);

                           tmpRl.setBackgroundDrawable(null);

                     }

                     hideArrows(llReordering);

                     if (max>1) {

                           rlCode.setBackgroundColor(Color.parseColor(“#89ce58”));

                           showDownArrow(numbers.indexOf(myString), rlCode);

                           showUpArrow(numbers.indexOf(myString), rlCode);

                     }

              }

       });

             

       rlayoutList.add(rlCodes);

       llReordering.addView(rlCodes);

       if (index<max) {

              View myView = new View(getApplicationContext());

              LinearLayout.LayoutParams tvParams = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, 1);

              myView.setLayoutParams(tvParams);

              myView.setBackgroundColor(Color.parseColor(“#FFA4A4A4”));

              llReordering.addView(myView);

       }         

}

In this method, we are adding a RelativeLayout with a pre-defined height of 70 and using the whole  screen width. In this layout, we are adding a TextView containing the string literal. We are also defining the onClickListener method for the relative layout. We’ll discuss it in short time. And at the end of the method, we have a conditional block to add a separator between the relative layouts that are appended sequentially in our list. This gives us a feel of native list which enriches the whole experience. The outcome looks like the figure 1.0.

Figure 1.0

Now, lets discuss the onClickListener method. First we convert the View to a RelativeLayout object and recover the tagged string object from the layout. Then, we iterate the RelativeLayouts list and match with the one clicked and remove and background drawables attached to the relative layout. This ensures that all the relative layout objects return to their non-selected state. After removing the backgrounds from all the relative layouts, we also need to remove the up & down arrows from all the relative layouts. So, we call the hideArrows() method passing in the relative layout list.

The method looks like this:

public void hideArrows(LinearLayout llAttachedCodes) {

       for(int i=0; i<llAttachedCodes.getChildCount(); i++) {

              View llView = llAttachedCodes.getChildAt(i);

              if (llView instanceof RelativeLayout) {

                     RelativeLayout rlView = (RelativeLayout)llView;

                     if (rlView.getChildCount()>0) {

                           for (int m=0; m<rlView.getChildCount(); m++) {

                                  View bView = rlView.getChildAt(m);

                                  if (bView instanceof Button) {

                                         Button b = (Button)bView;

                                         b.setVisibility(RelativeLayout.GONE);

                                  }

                           }

                     }

              }

       }

}

This method toggles the visibility of buttons that are displayed in the list items. We have to introspect the list item children to identify the Buttons and turn off their visibility.

Then we find this last conditional block in the onClickListener of the relative layout object.

if (max>1) {

       rlCode.setBackgroundColor(Color.parseColor(“#89ce58”));

       showDownArrow(numbers.indexOf(myString), rlCode);

       showUpArrow(numbers.indexOf(myString), rlCode);

}

After clicking an item, the screen changes like the one shown in figure 1.1.

Figure 1.1

This block is the one where the arrow buttons are shown in the list. First, we change the background color of the clicked layout to a shade of green to match our arrow images. Then we call showDownArrow() method which obviously shows the down arrow in the list. It takes two arguments, first, the current position of the numbers list and second, the relative layout itself.

public void showDownArrow(int index, RelativeLayout rlCode) {

       Button btnDownArrow = null;

       RelativeLayout rlActualCode = null;

       int rlPosition = rlayoutList.indexOf(rlCode);

       if (rlPosition!=rlayoutList.size()-1) {

              rlActualCode = rlayoutList.get(rlPosition+1);

       }

       else {

              rlActualCode = rlCode;

       }

       final String currentNumber = (String)rlActualCode.getTag();

       if (index >= 0 && index < max – 1){

              btnDownArrow = new Button(getApplicationContext());

              RelativeLayout.LayoutParams llParamsButton = new RelativeLayout.LayoutParams(70, 70);

              llParamsButton.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);

              llParamsButton.addRule(RelativeLayout.BELOW, 0);

              btnDownArrow.setLayoutParams(llParamsButton);

       btnDownArrow.setBackgroundDrawable(getResources().getDrawable(R.drawable.down_green));

              rlActualCode.addView(btnDownArrow);

       }

       if (btnDownArrow!=null) {

              btnDownArrow.setOnClickListener(new OnClickListener() {

                    

                     @Override

                     public void onClick(View v) {

                           int numberPosition=0;

                           String toShiftNumber = new String();

                           for (int s=0; s<max; s++) {

                                  if (currentNumber.equalsIgnoreCase(numbers.get(s))) {

                                         numberPosition = s;

                                         break;

                                  }

                           }

                          

                           if (numberPosition-1<numbers.size()) {

                                  toShiftNumber = numbers.get(numberPosition-1);

                                  numbers.set(numberPosition-1, currentNumber);

                                  numbers.set(numberPosition, toShiftNumber);

                           }

                           generateNumbers();

                           performRelativeClick(toShiftNumber);

                     }

              });

       }

}

In this method, we create a relative layout object from our arraylist containing the relative layouts taking the layout which sequentially comes next to the passed relative layout (rlCode). We do this because we need to show the down arrow just below the one clicked. After the relative layout is identified, we create the button setting the background drawable for down arrow image. But before we create the button, we need to verify that the layout where we are adding the arrow is not the last one. If the layout is the last one, then there is no point to move the object further down, it is already at the last. So we only add the down arrow button until we reach the layout which comes before the last one. Notice the position change of number “Six” in figure 1.2.

Figure 1.2

At the end of the method, we create an onClickListener() method for the created button, if at all it is created. In the click listener method, we exchange the position between the strings from the numbers arraylist using the set() method. After the strings have been switched, we refresh the UI by calling the generateNumbers() method.

The list of numbers is regenerated and the order that we wanted to be switched, is a reality. But the newly generated list doesn’t show our selections. Our selection should be moved down accordingly and the arrow buttons should be re-adjusted. But it didn’t happen. Well, the last method does that exactly.

public void performRelativeClick(String number) {

       for (int i=0; i<rlayoutList.size(); i++) {

              String myNumber = (String)rlayoutList.get(i).getTag();

              if (myNumber.equalsIgnoreCase(number)) {

                     rlayoutList.get(i).performClick();

              }

       }

}

Just like the method showing down arrow button, there is a method showing the up arrow button.

public void showUpArrow(int index, RelativeLayout rlCode) {

       Button btnUpArrow = null;

       RelativeLayout rlActualCode = null;

       int rlPosition = rlayoutList.indexOf(rlCode);

       if (rlPosition!=0) {

              rlActualCode = rlayoutList.get(rlPosition-1);

       }

       else {

              rlActualCode = rlCode;

       }

       final String currentNumber = (String)rlActualCode.getTag();

      if (index > 0 && index < max){

              btnUpArrow = new Button(getApplicationContext());

              RelativeLayout.LayoutParams llParamsButton = new RelativeLayout.LayoutParams(70, 70);

              llParamsButton.bottomMargin = -4;

              llParamsButton.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);

              llParamsButton.addRule(RelativeLayout.ABOVE, index + 3);

              btnUpArrow.setLayoutParams(llParamsButton);

              btnUpArrow.setId(index + 5);

                     btnUpArrow.setBackgroundDrawable(getResources().getDrawable(R.drawable.up_green));

              rlActualCode.addView(btnUpArrow);

       }

              if (btnUpArrow!=null) {

              btnUpArrow.setOnClickListener(new OnClickListener() {

                    

                     @Override

                     public void onClick(View v) {

                           int numberPosition=0;

                           for (int s=0; s<max; s++) {

                                  if (currentNumber.equalsIgnoreCase(numbers.get(s))) {

                                         numberPosition = s;

                                         break;

                                  }

                           }

                           String toShiftNumber = new String();

                           if (numberPosition+1>=0) {

                                  toShiftNumber = numbers.get(numberPosition+1);

                                  numbers.set(numberPosition+1, currentNumber);

                                  numbers.set(numberPosition, toShiftNumber);

                           }

                           generateNumbers();

                           performRelativeClick(toShiftNumber);

                     }

              });

       }

}

This method handles the up arrow buttons and its clicks. So this completes the re-ordering functionality in an Android list (not actual list). 

Figure 1.3

Finally, the numbers are positioned as they should be as shown in figure 1.3. Thanks!

Advertisements
By Movivation Labs

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s