VibratingTextView

please read the disclaimer
please read the formatting notes

.
Here it comes the first real widget in this library which by the way I am still unsure about its name or its components' names.

What's this really:



Anyway what is the idea behind this!?

To be able to move each letter,
someone could guess that each letter is actually a view in this video. Ok someone caught me! yes in reality it is!

In the sample project here is the xml for adding the VibratingTextView you see in the video:

<sherif.android.textview.VibratingTextView
	android:id="@+id/textView2"
	android:layout_width="wrap_content"
	android:textAppearance="?android:attr/textAppearanceLarge"
	android:layout_height="wrap_content"
	android:orientation="horizontal"
	android:text="outToRight" >
</sherif.android.textview.VibratingTextView>

Notice that it takes the usual attributes of a TextView. However also notice the android:orientation! Yes it is true it could have a vertical orientation as well.

Ok the real idea behind it is that a VibratingTextView is actually a LinearLayout with each letter mapped to a TextView in the LinearLayout. It is done this way (Remember you must conclude by now that VibratingTextView extends LinearLayout):
TextView[] array;
TextView view;
public VibratingTextView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs);
		view = new TextView(context, attrs, defStyle);
		update();
	}
public void update() {
		String mText = view.getText().toString();
		Context mContext = view.getContext();

		setBackgroundDrawable(view.getBackground());
		setPadding(view.getPaddingLeft(), view.getPaddingTop(), view
				.getPaddingRight(), view.getPaddingBottom());

		array = new TextView[mText.length()];
		for (int i = 0; i < mText.length(); i++) {
			array[i] = new TextView(mContext);
			array[i].setText(String.valueOf(mText.charAt(i)));
			array[i].setTextScaleX(view.getTextScaleX());
			array[i]
					.setTextSize(TypedValue.COMPLEX_UNIT_PX, view.getTextSize());
			array[i].setTextColor(view.getTextColors());
			addView(array[i]);
			Log.v("", array[i].getText().toString());
		}
		animating = new boolean[array.length];
		for (int i = 0; i < array.length; i++) {
			animating[i] = false;
		}
	}

Notice that first we initialize a TextView view using the attributes that are passed to the constructor ~F~. The VibratingTextView (this) has its padding and background set to the padding of this view ~F~.

Notice that there is an array of TextViews which is initialized. TextView i has its text set to character i of the text. Many attributes of the TextView are given to the elements of this array using setters ~F~.

Finally, animating is an array of boolean that reflects the state of each character (whether it is animating or not). This is also an ~F~ because I am not sure if this will be needed; however I kept it because it may be used to add some nice functionalities.

How does it vibrate? using the vibrate() function
private void vibrate() {
	for (int i = 0; i < array.length; i++) {
		animate(i);
	}
}
private void animate(int index) {
	Animation animation = randomizeAnimation();
	animation.setDuration(duration);
	animation.setInterpolator(new AccelerateInterpolator());
	animation.setAnimationListener(new AnimationsListener(index));
	array[index].startAnimation(animation);
	}
private Animation randomizeAnimation() {
	return new TranslateAnimation(Animation.RELATIVE_TO_SELF,
				0.0f, Animation.RELATIVE_TO_SELF, (float) Math.random() * 0.1f * (((float) Math.random() > 0.5) ? -1 : +1),
				Animation.RELATIVE_TO_SELF, 0.0f,
				Animation.RELATIVE_TO_SELF, (float) Math.random() * 0.1f * (((float) Math.random() > 0.5) ? -1 : +1));
	}

Pretty simple; the function is called on touch events. vibrate will call animate for each of the TextViews in array. aimate in turn will create an animation using randomizeAnimation which returns a TranslateAnimation that will cause the view to move in its own vicinity (not too far). randomizeAnimation is straight-forward and uses the Math's random function to create a random movement. Now after getting the animation using this randomization function, a duration is set (duration = 100) and an AccelerateInterpolator is set for the animation ~F~. Finally before starting the animation, a listener is set for it which is of type AnimationsListener which is a private class. I will not elaborate but it actually decides whether to continue animating and repeat this cycle (re generate an animation) or to stop.

This is working fine but of course I will work on enhancing it (this is just the first version).


Click here for Sample Project + Source Code (download) not always as up-to-date as github

Click here for Sample Project + Source Code (github)

Formatting notes:
Bold: a class in the android packages
BoldandItalic: a class created by me
Italic: a function or object in my code
back to top

Disclaimer:
There are some code snippets or statements that you may have comments on.
Please do not comment on any statement with a ~F~ beside it because this means on of these three things:
"THIS NEEDS TO BE FIXED"
"THIS IS NOT THE BEST PRACTICE"
"THERE IS A BETTER APPROACH"

In one word, I know about it and I will fix it in later commits.
back to top

2 comments:

  1. Hey serif,

    I saw you at stackoverflow (actually I answered to your custom XML attribute question on this ;-)
    As I stated before: Great idea! Wicked effect.

    I have a suggestion for future releases:
    I would recommend to uses an ordinary view for that and draw the actual letters yourself because this should be more performant a it would have a smaller memory footprint.

    Regards
    Knickedi (from Germany)

    ReplyDelete
  2. I will enhance on this but I am currently working on a ComboBox... It is almost done

    Thank you very much

    ReplyDelete