android 4.2的新特性layoutRtl,讓布局自動從右往左顯示
android4.2有一個新特性 layoutRtl,當然是對于開發者而言的,主要是方便開發者去支持阿拉伯語/波斯語等閱讀習慣是從右往左的。
可以在manifest的application標簽添加:android:supportsRtl 取值:true/false
這樣就可以打開layoutRtl這個功能。如果當前系統語言是阿拉伯語/波斯語,打開了這個功能的應用的布局就會自動變成從右往左的,當然前提是布局沒有寫死控件間的位置。
layoutRtl這個功能主要是在ViewGroup的子類ViewRootImpl在控制,具體怎么實現,還是需要自己去看看代碼,
如果布局變成了從右往左的話,焦點的移動也會有一些變化。EditText有一個標簽是用來讓輸入法提供類似“next”的按鈕的:imeoptions=“actionNext”。你按“next”的時候會發現,本來應該往右/下移動的光標,變成往左/上移動。
View焦點(focus)的控制方向是由FocuseFinder類進行控制的。你按下“next”的事件會由TextView的onEditorAction()進行處理。
public void onEditorAction(int actionCode) {
final Editor.InputContentType ict = mEditor == null ? null : mEditor.mInputContentType;
if (ict != null) {
if (ict.onEditorActionListener != null) {
if (ict.onEditorActionListener.onEditorAction(this,
actionCode, null)) {
return;
}
}
// This is the handling for some default action.
// Note that for backwards compatibility we don't do this
// default handling if explicit ime options have not been given,
// instead turning this into the normal enter key codes that an
// app may be expecting.
if (actionCode == EditorInfo.IME_ACTION_NEXT) {
View v = focusSearch(FOCUS_FORWARD);
if (v != null) {
if (!v.requestFocus(FOCUS_FORWARD)) {
throw new IllegalStateException("focus search returned a view " +
"that wasn't able to take focus!");
}
}
return;
} else if (actionCode == EditorInfo.IME_ACTION_PREVIOUS) {
View v = focusSearch(FOCUS_BACKWARD);
if (v != null) {
if (!v.requestFocus(FOCUS_BACKWARD)) {
throw new IllegalStateException("focus search returned a view " +
"that wasn't able to take focus!");
}
}
return;
} else if (actionCode == EditorInfo.IME_ACTION_DONE) {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null && imm.isActive(this)) {
imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
return;
}
}
ViewRootImpl viewRootImpl = getViewRootImpl();
if (viewRootImpl != null) {
long eventTime = SystemClock.uptimeMillis();
viewRootImpl.dispatchKeyFromIme(
new KeyEvent(eventTime, eventTime,
KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
| KeyEvent.FLAG_EDITOR_ACTION));
viewRootImpl.dispatchKeyFromIme(
new KeyEvent(SystemClock.uptimeMillis(), eventTime,
KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
| KeyEvent.FLAG_EDITOR_ACTION));
}
}
最終會調用FocuseFinder類的findNextFocus()方法來查找下一個可以獲得focus的view。
private View findNextFocus(ViewGroup root, View focused, Rect focusedRect,
int direction, ArrayList<View> focusables) {
if (focused != null) {
if (focusedRect == null) {
focusedRect = mFocusedRect;
}
// fill in interesting rect from focused
focused.getFocusedRect(focusedRect);
root.offsetDescendantRectToMyCoords(focused, focusedRect);
} else {
if (focusedRect == null) {
focusedRect = mFocusedRect;
// make up a rect at top left or bottom right of root
switch (direction) {
case View.FOCUS_RIGHT:
case View.FOCUS_DOWN:
setFocusTopLeft(root, focusedRect);
break;
case View.FOCUS_FORWARD:
//這里root是ViewRootImpl的實例
if (root.isLayoutRtl()) {
setFocusBottomRight(root, focusedRect);
} else {
setFocusTopLeft(root, focusedRect);
}
break;
case View.FOCUS_LEFT:
case View.FOCUS_UP:
setFocusBottomRight(root, focusedRect);
break;
case View.FOCUS_BACKWARD:
if (root.isLayoutRtl()) {
setFocusTopLeft(root, focusedRect);
} else {
setFocusBottomRight(root, focusedRect);
break;
}
}
}
}
switch (direction) {
case View.FOCUS_FORWARD:
case View.FOCUS_BACKWARD:
return findNextFocusInRelativeDirection(focusables, root, focused, focusedRect,
direction);
case View.FOCUS_UP:
case View.FOCUS_DOWN:
case View.FOCUS_LEFT:
case View.FOCUS_RIGHT:
return findNextFocusInAbsoluteDirection(focusables, root, focused,
focusedRect, direction);
default:
throw new IllegalArgumentException("Unknown direction: " + direction);
}
}private void setFocusBottomRight(ViewGroup root, Rect focusedRect) {
final int rootBottom = root.getScrollY() + root.getHeight();
final int rootRight = root.getScrollX() + root.getWidth();
focusedRect.set(rootRight, rootBottom, rootRight, rootBottom);
}
private void setFocusTopLeft(ViewGroup root, Rect focusedRect) {
final int rootTop = root.getScrollY();
final int rootLeft = root.getScrollX();
focusedRect.set(rootLeft, rootTop, rootLeft, rootTop);
}具體可以自己看代碼,上面的類名都添加了超鏈接到github
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!