View Javadoc

1   /***
2    *     Ambient - A music player for the Android platform
3    Copyright (C) 2007 Martin Vysny
4    
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9    
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14  
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package sk.baka.ambient.views;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import sk.baka.ambient.AmbientApplication;
25  import sk.baka.ambient.R;
26  import android.content.Context;
27  import android.content.res.TypedArray;
28  import android.graphics.Paint;
29  import android.util.AttributeSet;
30  import android.view.View;
31  import android.view.animation.Animation;
32  import android.view.animation.AnimationUtils;
33  import android.view.animation.TranslateAnimation;
34  import android.widget.TextSwitcher;
35  import android.widget.TextView;
36  import android.widget.ViewSwitcher;
37  
38  /***
39   * Scrolls given text from right to left. Starts from the beginning if no more
40   * text is to be scrolled.
41   * 
42   * @author Martin Vysny
43   */
44  public final class TextScroller extends TextSwitcher implements
45  		ViewSwitcher.ViewFactory {
46  
47  	private final long pauseMs;
48  
49  	/***
50  	 * @param context
51  	 * @param attrs
52  	 */
53  	public TextScroller(Context context, AttributeSet attrs) {
54  		super(context, attrs);
55  		final TypedArray a = getContext().obtainStyledAttributes(attrs,
56  				R.styleable.TextScroller);
57  		pauseMs = a.getResourceId(R.styleable.TextScroller_pauseMs, 2500);
58  		init();
59  	}
60  
61  	/***
62  	 * @param context
63  	 * @param pauseMs
64  	 */
65  	public TextScroller(Context context, final long pauseMs) {
66  		super(context);
67  		this.pauseMs = pauseMs;
68  		init();
69  	}
70  
71  	/***
72  	 * Creates new scroller instance.
73  	 */
74  	private void init() {
75  		fadeIn = AnimationUtils.loadAnimation(getContext(),
76  				android.R.anim.fade_in);
77  		fadeOut = AnimationUtils.loadAnimation(getContext(),
78  				android.R.anim.fade_out);
79  		slideInRight.setDuration(400);
80  		slideOutLeft.setDuration(400);
81  		textColor = getContext().getResources().getColor(R.color.textcolor);
82  		textParts.add("");
83  		textPaint = ((TextView) makeView()).getPaint();
84  		setFactory(this);
85  	}
86  
87  	/***
88  	 * The color of highlighted items in the list.
89  	 */
90  	private int textColor;
91  	private Animation fadeIn;
92  	private Animation fadeOut;
93  	private final Animation slideInRight = new TranslateAnimation(
94  			Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 0.0f,
95  			Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
96  	private final Animation slideOutLeft = new TranslateAnimation(
97  			Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF,
98  			-1.0f, Animation.RELATIVE_TO_SELF, 0.0f,
99  			Animation.RELATIVE_TO_SELF, 0.0f);
100 
101 	/***
102 	 * These parts are shown on the switcher.
103 	 */
104 	private final List<String> textParts = new ArrayList<String>();
105 
106 	/***
107 	 * Used to paint hint text.
108 	 */
109 	private Paint textPaint;
110 
111 	private String textToScroll = null;
112 
113 	/***
114 	 * Sets new text to the scroller. Resets the scroller to its initial value.
115 	 * 
116 	 * @param text
117 	 *            the text to set.
118 	 */
119 	public void setScrolledText(final String text) {
120 		if (getWidth() < 10) {
121 			textToScroll = text;
122 			return;
123 		}
124 		final boolean wasPaused = paused;
125 		pause();
126 		currentlyShown = 0;
127 		String remainingText = text;
128 		textParts.clear();
129 		while (true) {
130 			final int chars = textPaint.breakText(remainingText, true,
131 					getWidth(), null);
132 			if ((chars == 0) && (remainingText.length() != 0)) {
133 				textParts.clear();
134 				textToScroll = text;
135 				return;
136 			}
137 			textParts.add(remainingText.substring(0, chars).trim());
138 			if (chars >= remainingText.length())
139 				break;
140 			remainingText = remainingText.substring(chars);
141 		}
142 		setCurrentText(textParts.get(0));
143 		if (!wasPaused) {
144 			resume();
145 		}
146 	}
147 
148 	@Override
149 	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
150 		super.onSizeChanged(w, h, oldw, oldh);
151 		if ((w > 10) && (textToScroll != null)) {
152 			setScrolledText(textToScroll);
153 			textToScroll = null;
154 		}
155 	}
156 
157 	private boolean paused = false;
158 
159 	/***
160 	 * Pauses the scrolling.
161 	 */
162 	public void pause() {
163 		if (paused)
164 			return;
165 		paused = true;
166 		AmbientApplication.getHandler().removeCallbacks(rotateText);
167 	}
168 
169 	/***
170 	 * Resumes the scrolling. Fails if no text was previously set.
171 	 */
172 	public void resume() {
173 		if (textParts.isEmpty()) {
174 			throw new IllegalArgumentException("No text set");
175 		}
176 		if (!paused)
177 			return;
178 		if (textParts.size() > 1) {
179 			AmbientApplication.getHandler().postDelayed(rotateText, pauseMs);
180 		}
181 		paused = false;
182 	}
183 
184 	/***
185 	 * Currently shown text, index to the {@link #textParts} list.
186 	 */
187 	private int currentlyShown = 0;
188 
189 	/***
190 	 * Executed periodically in handler, serves for text rotating.
191 	 */
192 	private final Runnable rotateText = new Runnable() {
193 		public void run() {
194 			if (currentlyShown == 0) {
195 				setInAnimation(slideInRight);
196 				setOutAnimation(slideOutLeft);
197 				currentlyShown++;
198 			} else if (currentlyShown == textParts.size() - 1) {
199 				setInAnimation(fadeIn);
200 				setOutAnimation(fadeOut);
201 				currentlyShown = 0;
202 			} else {
203 				currentlyShown++;
204 			}
205 			final String newText = textParts.get(currentlyShown);
206 			TextScroller.this.setText(newText);
207 			AmbientApplication.getHandler().postDelayed(this, pauseMs);
208 		}
209 	};
210 
211 	public View makeView() {
212 		final TextView t = new TextView(getContext());
213 		t.setTextColor(textColor);
214 		return t;
215 	}
216 }