Thursday, June 13, 2013

Create horizontal menu for Android-based applications

In this article I want to share one of the ways to develop a nice animated menu or text horizontal list.




Concept

Create horizontal menu for Android-based applicationsCreate horizontal menu for Android-based applications

To implement such a list, I'm using a TextSwitcher. This element contains a TextView, which we may customize on your own.
TextSwitcher useful for changing animated text. We will use 3 TextSwitcher. Main Switcher used to identify the current list element, and the side - for navigation options and display elements of the next.
For the shadowing effect, we will create a gradient TextView with the transition from transparent to the desired color.

Preparing resources

To start the animation will develop change the text from left to right and right to left.
Source code anim/push_left_in.xml
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="300"
        android:fromXDelta="-100%p"
        android:toXDelta="0" />

    <alpha
        android:duration="300"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />
</set>

Source code anim/push_left_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="300"
        android:fromXDelta="0"
        android:toXDelta="-100%p" />

    <alpha
        android:duration="300"
        android:fromAlpha="1.0"
        android:toAlpha="0.0" />
</set>

Source code anim/push_right_in.xml
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="300"
        android:fromXDelta="100%p"
        android:toXDelta="0" />

    <alpha
        android:duration="300"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />
</set>

Source code anim/push_right_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="300"
        android:fromXDelta="0"
        android:toXDelta="100%p" />

    <alpha
        android:duration="300"
        android:fromAlpha="1.0"
        android:toAlpha="0.0" />
</set>

For Gradient TextView to describe its properties:
Source code values/attrs.xml
<resources>

    <declare-styleable name="GradientTextView">
        <attr name="colorStartGradient" format="integer" />
        <attr name="colorEndGradient" format="integer" />
    </declare-styleable>

</resources>

As well add color for the gradient:
Source code values/colors.xml
<resources>
    <color name="textview_start_gradient">#00ffffff</color>
       <color name="textview_end_gradient">#88ffffff</color>
</resources>

Develop the the main layout of the window, which will contain our animated menu:
Source code layout/main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <TextSwitcher
        android:id="@+id/scoreboard_location_left"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <TextSwitcher
        android:id="@+id/scoreboard_location"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <TextSwitcher
        android:id="@+id/scoreboard_location_right"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

</LinearLayout>

TextSwitcher contains a TextView. Our project will use two types of text controls: normal (for the central element) and the gradient (for side elements).
Source code layout/central_textview.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:id="@+id/textview" />

Source code layout/gradient_textview.xml
<org.snowpard.proects.twenty.GradientTextView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/org.snowpard.proects.twenty"
    android:id="@+id/textview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    app:colorEndGradient="@color/textview_end_gradient"
    app:colorStartGradient="@color/textview_start_gradient" />

Developing

  • Create Gradient TextView
public class GradientTextView extends TextView {

 private int colorStartGradient, colorEndGradient;
 private boolean direction;
 private LinearGradient gradient; 
 
 public GradientTextView(Context context, AttributeSet attrs) {
  super(context, attrs);

  TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.GradientTextView);
  colorStartGradient = a.getColor(R.styleable.GradientTextView_colorStartGradient, -2);
  colorEndGradient = a.getColor(R.styleable.GradientTextView_colorEndGradient, -2);
  direction = false;
 }
 
 public void setDirection(boolean direction)
 {
  this.direction = direction;
 }

 @Override
 protected void onDraw(Canvas canvas) {
  if (colorStartGradient != -2 && colorEndGradient != -2)
  {
   gradient = new LinearGradient(direction ? getWidth() : 0, 0, direction ? 0 : getWidth(), 0, colorStartGradient,
      colorEndGradient, TileMode.CLAMP);
    

   getPaint().setShader(gradient); 
   
  }
  super.onDraw(canvas);
 }

}
  • Development of the main class MainActivity, work with a horizontal menu.
Add a constant in the class, which will be responsible for the direction of the animation.
public static final int DIRECTION_NONE  = 0;
public static final int DIRECTION_LEFT  = 1;
public static final int DIRECTION_RIGHT  = 2;

private int current_direction = DIRECTION_RIGHT;

We describe the controls and animations that will be used to operate the menu:
private TextSwitcher switcher, switcher_left, switcher_right;
private Animation in_left, in_right, out_left, out_right;

And to add an array of items for the horizontal menu and the index for the identification of the current element:
private String[] locations = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"};
private int current_index;

Develop a method of for working with a horizontal menu:

- setAnimation: to set the desired animation to change the text
private void setAnimation(TextSwitcher switcher, Animation in, Animation out)
 {
  switcher.setInAnimation(in);
  switcher.setOutAnimation(out);
 }

- initSwitch: initialization TextSwitcher
private void initSwitch(TextSwitcher switcher, final int place, Animation in, Animation out, final Context context)
 {  
  switcher.setFactory(new ViewFactory() {
   
   @Override
   public View makeView() {
    TextView view = (TextView)LayoutInflater.from(context).inflate((place == 0) ? R.layout.central_textview: R.layout.gradient_textview, null).findViewById(R.id.textview);
    if (view instanceof GradientTextView)
     ((GradientTextView)view).setDirection(place != 1);
    return view;
   }
  });
  setAnimation(switcher, in, out);
 }

- setSwitch: change an item in the horizontal menu
private void setSwitch(int direction)
 {
  boolean isUpdate = false;
  if (direction == DIRECTION_LEFT && current_index > 0)
  {
   isUpdate = true;
   current_index--;
  }
  else if (direction == DIRECTION_RIGHT && current_index < locations.length - 1)
  {
   isUpdate = true;
   current_index++;
  } else if (direction == DIRECTION_NONE)
   isUpdate = true; 
  if (isUpdate)
  {
   if (direction != current_direction && direction != DIRECTION_NONE)
   {
    current_direction = direction;
    if (current_direction == DIRECTION_RIGHT)
    {
     setAnimation(switcher_left, in_right, out_left);
     setAnimation(switcher, in_right, out_left);
     setAnimation(switcher_right, in_right, out_left);
    } else 
    {
     setAnimation(switcher_left, in_left, out_right);
     setAnimation(switcher, in_left, out_right);
     setAnimation(switcher_right, in_left, out_right);
    }
   }
   
   if (current_index - 1 >= 0)
    switcher_left.setText(locations[current_index - 1]);
   else 
    switcher_left.setText("");
   
   switcher.setText(locations[current_index]);
   
   if (current_index + 1 <= locations.length - 1)
    switcher_right.setText(locations[current_index + 1]);
   else 
    switcher_right.setText("");
  }
 }

Now you need to initialize all in the method onCreate() of our Activity:
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  
  in_left = AnimationUtils.loadAnimation(this,
                R.anim.push_left_in);
  in_right = AnimationUtils.loadAnimation(this,
                R.anim.push_right_in);
  out_right = AnimationUtils.loadAnimation(this,
                R.anim.push_right_out);
  out_left = AnimationUtils.loadAnimation(this,
                R.anim.push_left_out);
  
        switcher = (TextSwitcher) findViewById(R.id.scoreboard_location);
        switcher_left = (TextSwitcher) findViewById(R.id.scoreboard_location_left);
        switcher_right = (TextSwitcher) findViewById(R.id.scoreboard_location_right);
        
        initSwitch(switcher, 0, in_right, out_left, this);
        initSwitch(switcher_left, 1, in_right, out_left, this);
        initSwitch(switcher_right, 2, in_right, out_left, this);
        
        switcher_left.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    setSwitch(DIRECTION_LEFT);
   }
  });
        switcher_right.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    setSwitch(DIRECTION_RIGHT);
   }
  });
        
        setSwitch(DIRECTION_NONE);
 }

Links

  • The source codes of this project can be downloaded here: zip