Introduction
With my experience, customize a View is really a difficult task. Fortunately, Android supports SurfaceView, which is useful in view customize.
In this article, I guided the way to custom a Half Circle list view. Today, I will also use SurfaceView o custom a auto horizontal scroll view.
Background
You should spend time to read SurfaceView document in Android developer website before reading this article.
Using the code
Animation.java
To auto slide list view from right to left, the idea is we will update the coordinate of each item in list view and draw it continuously in a background thread.
How to update the coordinate of each item continuously?
Suppose that, from time t1 to time t2, we must translate item from coordinate x1, to x2. The problem is, at time t, x = ? The formula will be easy:
x = x1 + t * (x2-x1) / (t2-t1)
Base on idea above, I made a simple Animation class which is used to calculate the current value, with below properties:
mStartValue
: The beginning value when animation starting. mEndValue
: The final value when animation ending. mDuration
: The duration to change value from mStartValue to mEndValue. mStartTime
: The time animation starting. At the time animation is started, it is got by
System.currentTimeMillis().
mEndTime
: The time animation ending. mEndTime
= mStartTime
+ mDuration
.
The method to get the current value at specified time will be:
public float getCurrentValue(long currentTime) {
float currentValue = mStartValue + (currentTime)
* (mEndValue - mStartValue) / mDuration;
if (currentTime > mEndTime) {
currentValue = mEndValue;
}
return currentValue;
}
Extends above class, I made TranslateXAnimation.java
public class TranslateX extends Animation {
public TranslateX() {
super(Type.Translate);
}
}
Offcourse, we can make more Animation such as: FadeAnimation, ScaleAnimation... with the same idea. In this article, I use TranslateXAnimation only.
ImageItem.java
This object is an item of ListView.
private class ImageItem {
public float x;
public float y;
public Bitmap bitmap;
public TranslateXAnimation translateX;
}
x
and y:
is the coordinate of image item. The coordinate will be updated at real time. Base on x, y, item will be drawn in a thread by using Canvas canvas.drawBitmap(bitmap, x, y, paint);
translateX
: when start to auto scrolling, item will be executed this animation. It will updated the x
at runtime:
x = translateX.getCurrentValue(System.currentTimeMillis() - translateX.mStartTime);
And item will be drawn by Canvas.
canvas.drawBitmap(bitmap, x, y, paint);
AutoHorizontalScrollView.java
This class is extends from SurfaceView which keeps an array list of ImageItem.
How to auto scroll for each 2 seconds?
I keep a variable startDisplayTime
in this list view with idea:
- From the first time AutoHorizontalScrollView is being displayed,
startDisplayTime =
System.currentTimeMillis().
- When runtime, if
<span style="font-size: 14px;"> </span>^__em style="font-size: 14px;">startDisplayTime
>= 2 seconds, - Start auto scroll.
- Update
startDisplayTime = System.currentTimeMillis()
How to looping?
Looping means that, when the last item is being began to display from the right, the next right item will be the first item:)
If we have ITEM_WIDTH
is the width of each list item, we will update its x coordinate:
if (item.x <= -ITEM_WIDTH) {
item.x = VIEW_WIDTH - 2 * ITEM_WIDTH;
}
How to draw list item?
It is a easy work, because we only draw all item of list in background thread continuously.
Canvas canvas = getHolder().lockCanvas();
if (canvas == null) {
return;
}
canvas.save();
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
for (int i = 0; i < items.size(); i++) {
ImageItem item = items.get(i);
item.draw(canvas);
}
canvas.restore();
getHolder().unlockCanvasAndPost(canvas);
ImageItem.draw()
public void draw(Canvas canvas) {
canvas.save();
if (translateX != null && !translateX.isEnded()) {
x = translateX.getCurrentValue(System.currentTimeMillis()
- translateX.mStartTime);
} else {
}
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setAntiAlias(true);
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();
}
I put here the class diagram for easy understanding.
Advance animation
20130906.
I have finished the article to guide the way to execute animation in SurfaceView. Base on the animation in this article, I will apply it to improve function of this list view? What do you think if I added more requirement as below:
- All item will be has alpha is 100 at default.
- The last right item will be scale from 1 to 1.5 and its alpha will be changed from 100 to 255 when slide from the right to the left.
- The center item will be scale down 1.5 to 1 and its alpha will be changed from 255 to 100 when slide from the right to the left.
Base on Animation class, it is easy to make the ScaleXAnimation, ScaleYAnimation, AlphaAnimation.
The ImageItem will be added more properties:
scaleX
: keep the scale ratio scaleY
: keep the scale ratio alpha
: Keep alpha value for fade in/out animation. animations
: The array list of animation which is executed.
With AutoHorizontalScrollView.java, I added:
firstItemPos
: The position in list items of the first item in the left. Default is 0 from starting. secondItemPos
: The position in list items of the first item in the center. Default is 1 from starting. thirdItemPos
: The position in list items of the first item in the center. Default is 2 from starting.
Animation
When slide, if the position is thirdItemPos , beside the TranslateXAnimation, add to it:
ScaleXAnimation
ScaleXAnimation scaleX = new ScaleXAnimation();
scaleX.mStartTime = System.currentTimeMillis();
scaleX.mDuration = 500;
scaleX.mEndTime = System.currentTimeMillis() + 500;
scaleX.mStartValue = 1f;
scaleX.mEndValue = 1.5f;
item.animations.add(scaleX);
ScaleYAnimation
ScaleYAnimation scaleY = new ScaleYAnimation();
scaleY.mStartTime = System.currentTimeMillis();
scaleY.mDuration = 500;
scaleY.mEndTime = System.currentTimeMillis() + 500;
scaleY.mStartValue = 1f;
scaleY.mEndValue = 1.5f;
item.animations.add(scaleY);
And AlphaAnimation
AlphaAnimation alpha = new AlphaAnimation();
alpha.mStartTime = System.currentTimeMillis();
alpha.mDuration = 500;
alpha.mEndTime = System.currentTimeMillis() + 500;
alpha.mStartValue = 150;
alpha.mEndValue = 255;
item.animations.add(alpha);
And if it is the center position secondItemPos
, add to it
ScaleXAnimation
ScaleXAnimation scaleX = new ScaleXAnimation();
scaleX.mStartTime = System.currentTimeMillis();
scaleX.mDuration = 500;
scaleX.mEndTime = System.currentTimeMillis() + 500;
scaleX.mStartValue = 1.5f;
scaleX.mEndValue = 1f;
item.animations.add(scaleX);
ScaleYAnimation
ScaleYAnimation scaleY = new ScaleYAnimation();
scaleY.mStartTime = System.currentTimeMillis();
scaleY.mDuration = 500;
scaleY.mEndTime = System.currentTimeMillis() + 500;
scaleY.mStartValue = 1.5f;
scaleY.mEndValue = 1f;
item.animations.add(scaleY);
And AlphaAnimation
AlphaAnimation alpha = new AlphaAnimation();
alpha.mStartTime = System.currentTimeMillis();
alpha.mDuration = 500;
alpha.mEndTime = System.currentTimeMillis() + 500;
alpha.mStartValue = 255;
alpha.mEndValue = 100;
And 3 three position will be updated as below:
thirdItemPos++;
if (thirdItemPos == items.size()) {
thirdItemPos = 0;
}
secondItemPos++;
if (secondItemPos == items.size()) {
secondItemPos = 0;
}
firstItemPos++;
if (firstItemPos == items.size()) {
firstItemPos = 0;
}
Draw
To draw ItemImage, do as below:
for (int i = 0; i < animations.size(); i++) {
Animation animation = animations.get(i);
if (animation.isStarted()) {
if (!animation.isEnded()) {
if (animation.mType == Type.TranslateX) {
x = animation
.getCurrentValue(System.currentTimeMillis()
- animation.mStartTime);
} else if (animation.mType == Type.ScaleX) {
scaleX = animation
.getCurrentValue(System.currentTimeMillis()
- animation.mStartTime);
} else if (animation.mType == Type.ScaleY) {
scaleY = animation
.getCurrentValue(System.currentTimeMillis()
- animation.mStartTime);
} else if (animation.mType == Type.Alpha) {
alpha = (int) animation
.getCurrentValue(System.currentTimeMillis()
- animation.mStartTime);
}
} else {
animations.remove(i);
}
}
}
paint.setAlpha(alpha);
canvas.scale(scaleX, scaleX, x, y);
canvas.drawBitmap(bitmap, x, y, paint);
You can download AdvandeHorizontalAutoScrollListView.zip to view the result.
HISTORY
20130905: First created.
20130906: After finishing the article about SurfaceView animation add alpha, scaleX, scaleY animation to it.