ScrollingMovementMethod.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.text.method; 18 19import android.util.Log; 20import android.view.KeyEvent; 21import android.view.MotionEvent; 22import android.text.*; 23import android.widget.TextView; 24import android.view.View; 25 26public class 27ScrollingMovementMethod 28implements MovementMethod 29{ 30 /** 31 * Scrolls the text to the left if possible. 32 */ 33 protected boolean left(TextView widget, Spannable buffer) { 34 Layout layout = widget.getLayout(); 35 36 int scrolly = widget.getScrollY(); 37 int scr = widget.getScrollX(); 38 int em = Math.round(layout.getPaint().getFontSpacing()); 39 40 int padding = widget.getTotalPaddingTop() + 41 widget.getTotalPaddingBottom(); 42 int top = layout.getLineForVertical(scrolly); 43 int bottom = layout.getLineForVertical(scrolly + widget.getHeight() - 44 padding); 45 int left = Integer.MAX_VALUE; 46 47 for (int i = top; i <= bottom; i++) { 48 left = (int) Math.min(left, layout.getLineLeft(i)); 49 } 50 51 if (scr > left) { 52 int s = Math.max(scr - em, left); 53 widget.scrollTo(s, widget.getScrollY()); 54 return true; 55 } 56 57 return false; 58 } 59 60 /** 61 * Scrolls the text to the right if possible. 62 */ 63 protected boolean right(TextView widget, Spannable buffer) { 64 Layout layout = widget.getLayout(); 65 66 int scrolly = widget.getScrollY(); 67 int scr = widget.getScrollX(); 68 int em = Math.round(layout.getPaint().getFontSpacing()); 69 70 int padding = widget.getTotalPaddingTop() + 71 widget.getTotalPaddingBottom(); 72 int top = layout.getLineForVertical(scrolly); 73 int bottom = layout.getLineForVertical(scrolly + widget.getHeight() - 74 padding); 75 int right = 0; 76 77 for (int i = top; i <= bottom; i++) { 78 right = (int) Math.max(right, layout.getLineRight(i)); 79 } 80 81 padding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight(); 82 if (scr < right - (widget.getWidth() - padding)) { 83 int s = Math.min(scr + em, right - (widget.getWidth() - padding)); 84 widget.scrollTo(s, widget.getScrollY()); 85 return true; 86 } 87 88 return false; 89 } 90 91 /** 92 * Scrolls the text up if possible. 93 */ 94 protected boolean up(TextView widget, Spannable buffer) { 95 Layout layout = widget.getLayout(); 96 97 int areatop = widget.getScrollY(); 98 int line = layout.getLineForVertical(areatop); 99 int linetop = layout.getLineTop(line); 100 101 // If the top line is partially visible, bring it all the way 102 // into view; otherwise, bring the previous line into view. 103 if (areatop == linetop) 104 line--; 105 106 if (line >= 0) { 107 Touch.scrollTo(widget, layout, 108 widget.getScrollX(), layout.getLineTop(line)); 109 return true; 110 } 111 112 return false; 113 } 114 115 /** 116 * Scrolls the text down if possible. 117 */ 118 protected boolean down(TextView widget, Spannable buffer) { 119 Layout layout = widget.getLayout(); 120 121 int padding = widget.getTotalPaddingTop() + 122 widget.getTotalPaddingBottom(); 123 124 int areabot = widget.getScrollY() + widget.getHeight() - padding; 125 int line = layout.getLineForVertical(areabot); 126 127 if (layout.getLineTop(line+1) < areabot + 1) { 128 // Less than a pixel of this line is out of view, 129 // so we must have tried to make it entirely in view 130 // and now want the next line to be in view instead. 131 132 line++; 133 } 134 135 if (line <= layout.getLineCount() - 1) { 136 widget.scrollTo(widget.getScrollX(), layout.getLineTop(line+1) - 137 (widget.getHeight() - padding)); 138 Touch.scrollTo(widget, layout, 139 widget.getScrollX(), widget.getScrollY()); 140 return true; 141 } 142 143 return false; 144 } 145 146 public boolean onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { 147 return executeDown(widget, buffer, keyCode); 148 } 149 150 private boolean executeDown(TextView widget, Spannable buffer, int keyCode) { 151 boolean handled = false; 152 153 switch (keyCode) { 154 case KeyEvent.KEYCODE_DPAD_LEFT: 155 handled |= left(widget, buffer); 156 break; 157 158 case KeyEvent.KEYCODE_DPAD_RIGHT: 159 handled |= right(widget, buffer); 160 break; 161 162 case KeyEvent.KEYCODE_DPAD_UP: 163 handled |= up(widget, buffer); 164 break; 165 166 case KeyEvent.KEYCODE_DPAD_DOWN: 167 handled |= down(widget, buffer); 168 break; 169 } 170 171 return handled; 172 } 173 174 public boolean onKeyUp(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { 175 return false; 176 } 177 178 public boolean onKeyOther(TextView view, Spannable text, KeyEvent event) { 179 int code = event.getKeyCode(); 180 if (code != KeyEvent.KEYCODE_UNKNOWN 181 && event.getAction() == KeyEvent.ACTION_MULTIPLE) { 182 int repeat = event.getRepeatCount(); 183 boolean first = true; 184 boolean handled = false; 185 while ((--repeat) > 0) { 186 if (first && executeDown(view, text, code)) { 187 handled = true; 188 MetaKeyKeyListener.adjustMetaAfterKeypress(text); 189 MetaKeyKeyListener.resetLockedMeta(text); 190 } 191 first = false; 192 } 193 return handled; 194 } 195 return false; 196 } 197 198 public boolean onTrackballEvent(TextView widget, Spannable text, 199 MotionEvent event) { 200 return false; 201 } 202 203 public boolean onTouchEvent(TextView widget, Spannable buffer, 204 MotionEvent event) { 205 return Touch.onTouchEvent(widget, buffer, event); 206 } 207 208 public void initialize(TextView widget, Spannable text) { } 209 210 public boolean canSelectArbitrarily() { 211 return false; 212 } 213 214 public void onTakeFocus(TextView widget, Spannable text, int dir) { 215 Layout layout = widget.getLayout(); 216 217 if (layout != null && (dir & View.FOCUS_FORWARD) != 0) { 218 widget.scrollTo(widget.getScrollX(), 219 layout.getLineTop(0)); 220 } 221 if (layout != null && (dir & View.FOCUS_BACKWARD) != 0) { 222 int padding = widget.getTotalPaddingTop() + 223 widget.getTotalPaddingBottom(); 224 int line = layout.getLineCount() - 1; 225 226 widget.scrollTo(widget.getScrollX(), 227 layout.getLineTop(line+1) - 228 (widget.getHeight() - padding)); 229 } 230 } 231 232 public static MovementMethod getInstance() { 233 if (sInstance == null) 234 sInstance = new ScrollingMovementMethod(); 235 236 return sInstance; 237 } 238 239 private static ScrollingMovementMethod sInstance; 240} 241