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 }