Reputation: 1415
I'm working on Android app which main purpose is to display CNN breaking news styled bar on the bottom and some pictures. I created two custom views, one for displaying photos and the second one for displaying bar. It displays one picture at a time for specified amount of time and swaps current picture with next one from the queue.
To animate text in bottom bar I used canvas, onDraw() and handler.postDelayed. This solution gives poor result. Text movement is not smooth especially when it comes to swap image.
What should I use instead of canvas? Is there any OpenGL-based lib which could make this task relatively painless? I tried to use AndEngine, but its lack of documentation and problems with threads discouraged me to working with it anymore.
public class Infobar extends View {
private List<Message> messages;
private Handler handler;
private Paint boxPaint;
private Paint defaultTextPaint;
private Paint importantTextPaint;
private long offset = 0;
private long maxOffset = 1000;
private int textWidth = 1000;
private int textHeight = 50;
private int measuredWidth;
private int measuredHeight;
private Runnable animateRunnable = new Runnable() {
public void run() {
animateMessage();
}
};
long startTime = new Date().getTime();
private int backgroundCol = Color.parseColor("#ffff00");
private int textColor = Color.parseColor("#000000");
private static final int FRAME_DELAY = 10;
private static final int FRAME_SHIFT = 3;
private static final int EMPTY_SPACE = 2;
private static final String SEPARATOR = " ✩ ";
private static final int TEXT_SIZE = 35;
public Infobar(Context context, AttributeSet attrs) {
super(context, attrs);
handler = new Handler();
messages = new ArrayList<Message>();
boxPaint = new Paint();
defaultTextPaint = new Paint();
defaultTextPaint.setColor(getResources().getColor(R.color.info_bar_default_text_color));
importantTextPaint = new Paint();
importantTextPaint.setColor(getResources().getColor(R.color.info_bar_important_text_color));
handler.postDelayed(animateRunnable, FRAME_DELAY);
}
public void setMessagesList(List<Message> list) {
messages = list;
}
public void setBackgroundColor(String color) {
backgroundCol = Color.parseColor(color);
}
public void setTextColor(String color) {
textColor = Color.parseColor(color);
}
public List<Message> getMessagesList() {
return messages;
}
private String getMessagesString() {
StringBuilder builder = new StringBuilder();
for(Message message : messages) {
builder.append(message.content);
if(messages.indexOf(message) != (messages.size() - 1)) {
builder.append(SEPARATOR);
}
}
return builder.toString();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measuredWidth = getMeasuredWidth();
measuredHeight = getMeasuredHeight();
}
@Override
protected void onDraw(Canvas canvas) {
drawBackground(canvas, false);
drawMessage(canvas, getMessagesString());
super.onDraw(canvas);
}
private void drawBackground(Canvas canvas, boolean important) {
boxPaint.setColor(backgroundCol) ;
canvas.drawRect(0, 0, measuredWidth, measuredHeight, boxPaint);
}
private void drawMessage(Canvas canvas, String message) {
defaultTextPaint.setTextSize(TEXT_SIZE);
Rect bounds = new Rect();
defaultTextPaint.getTextBounds(message, 0, message.length(), bounds);
defaultTextPaint.setColor(textColor);
textWidth = bounds.width();
textHeight = bounds.height();
int positionX = measuredWidth - (int)offset;
int positionY = measuredHeight - textHeight/2;
if(offset > (measuredWidth + textWidth)) {
offset = 0;
positionX = measuredWidth;
}
canvas.drawText(message, positionX, positionY, defaultTextPaint);
}
private void animateMessage() {
offset += FRAME_SHIFT;
//offset = Math.round((new Date().getTime() - startTime) * 0.2) % (measuredWidth + textWidth);
invalidate();
handler.removeCallbacks(animateRunnable);
handler.postDelayed(animateRunnable, FRAME_DELAY);
}
}
Upvotes: 4
Views: 5235
Reputation: 2189
Unless there is a specific reason, you can use the built-in marquee function of TextView:
<LinearLayout>
<TextView
android:id="@+id/myText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lines="1"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:text="Your long text goes here. You can also change it programmatically" />
</LinearLayout>
Then in the activity code:
TextView myText=(TextView) findViewById(R.id.myText);
myText.setSelected(true); //needs this to work
Upvotes: 6