Android ApiDemos示例解析(118):Views->Focus->4. Internal Selection
上一篇:http://www.zzzyk.com/kf/201208/146799.html使用方向键或是traceball 移动UI焦点时,有一些UI控件,如Listview ,GridView 内部可以带有子UI (如列表项,Cell项),当Focus移动到这类UI控件后,再使用使用方向键或是traceball 可以在Listview 或是 GridView 内部移动当前选中的列表项或是Cell项等。
本例介绍了一个自定义UI控件InternalSelectionView ,自定义UI控件的步骤可以参见Android ApiDemos示例解析(109):Views->Custom
InternalSelectionView 可以显示一个矩形列表,矩形的宽度为View的宽度,允许自定义列表的行数,矩形的高度为View的高度平分为列表的行数。缺省行数为5.
其onDraw 显示 矩形,并以高亮(红色)显示当前选中的矩形。否则以黑色显示.
[java]
@Override
protected void onDraw(Canvas canvas) {
...
// draw forground rect
if (i == mSelectedRow && hasFocus()) {
mPainter.setColor(Color.RED);
mPainter.setAlpha(0xF0);
mTextPaint.setAlpha(0xFF);
} else {
mPainter.setColor(Color.GREEN);
mPainter.setAlpha(0x40);
mTextPaint.setAlpha(0xF0);
}
...
}
@Override
protected void onDraw(Canvas canvas) {
...
// draw forground rect
if (i == mSelectedRow && hasFocus()) {
mPainter.setColor(Color.RED);
mPainter.setAlpha(0xF0);
mTextPaint.setAlpha(0xFF);
} else {
mPainter.setColor(Color.GREEN);
mPainter.setAlpha(0x40);
mTextPaint.setAlpha(0xF0);
}
...
}
注:黑色背景矩形显示看不大清楚,这里改为绿色。
和UI焦点(Focus)相关的几个方法如下:
1. 处理方向键“上”,“下” ,InternalSelectionView 显示了一个纵向矩形列表,可以使用“上”,“下”键移动InternalSelectionView 当前选中的矩形。
[java
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch(event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_UP:
if (mSelectedRow > 0) {
mSelectedRow--;
invalidate();
ensureRectVisible();
return true;
}
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
if (mSelectedRow < (mNumRows - 1)) {
mSelectedRow++;
invalidate();
ensureRectVisible();
return true;
}
break;
}
return false;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch(event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_UP:
if (mSelectedRow > 0) {
mSelectedRow--;
invalidate();
ensureRectVisible();
return true;
}
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
if (mSelectedRow < (mNumRows - 1)) {
mSelectedRow++;
invalidate();
ensureRectVisible();
return true;
}
break;
}
return false;
}
2. 重载getFocusedRect 方法,设置被选中区域矩形框大小, 缺省情况(对应没有内部选择功能的UI控件) getFocusedRect 和 getDrawingRect大小相同,也就是和View大小相同。当将UI焦点从本控件移动到下一个UI控件时,Android系统将根据本UI控件的Focused Rect位置根据UI焦点移动的方向找到和这个Focused Rect距离最近的下一个UI控件。 对应支持内部选择的View(如本例或ListView)getFocusedRect 应正确设置选中区域矩形的大小:
[java]
@Override
public void getFocusedRect(Rect r) {
getRectForRow(r, mSelectedRow);
}
public void getRectForRow(Rect rect, int row) {
final int rowHeight = getRowHeight();
final int top = getPaddingTop() + row * rowHeight;
rect.set(getPaddingLeft(),
top,
getWidth() - getPaddingRight(),
top + rowHeight);
}
@Override
public void getFocusedRect(Rect r) {
getRectForRow(r, mSelectedRow);
}
public void getRectForRow(Rect rect, int row) {
final int rowHeight = getRowHeight();
final int top = getPaddingTop() + row * rowHeight;
rect.set(getPaddingLeft(),
top,
getWidth() - getPaddingRight(),
top + rowHeight);
}
本例将Focused Rect 设置成当前选中的矩形的大小。
3. 重载 onFocusChanged ,这个方法在当前UI View Focus状态发生变化时调用,状态为取得焦点和失去焦点。 重载时记住要调用基类的方法以保证标准Focus移动行为。
[java]
@Override
protected void onFocusChanged(boolean focused,
int direction,
Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction,
previouslyFocusedRect);
if (focused) {
switch (direction) {
case View.FOCUS_DOWN:
mSelectedRow = 0;
break;
case View.FOCUS_UP:
mSelectedRow = mNumRows - 1;
break;
case View.FOCUS_LEFT: // fall through
case View.FOCUS_RIGHT:
// set the row that is closest to the rect
if (previouslyFocusedRect != null) {
int y = previouslyFocusedRect.top
+ (previouslyFocusedRect.height() / 2);
int yPerRow = getHeight() / mNumRows;
mSelectedRow = y / yPerRow;
} else {
mSelectedRow = 0;
}
break;
default:
// can't gleam any useful information about what internal
// selection should be...
return;
}
invalidate();
}
}
@Override
protected void onFocusChanged(boolean focused,
int direction,
Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction,
previouslyFocusedRect);
if (focused) {
switch (direction) {
case View.FOCUS_DOWN:
mSelectedRow = 0;
break;
case View.FOCUS_UP:
mSelectedRow = mNumRows - 1;
break;
case View.FOCUS_LEFT: // fall through
case View.FOCUS_RIGHT:
// set the row that is closest to the rect
if (previouslyFocusedRect != null) {
int y = previouslyFocusedRect.top
+ (previouslyFocusedRect.height() / 2);
int yPerRow = getHeight() / mNumRows;
mSelectedRow = y / yPerRow;
} else {
mSelectedRow = 0;
}
break;
default:
// can't gleam any useful information about what internal
// selection should be...
return;
}
invalidate();
}
}
函数参数:
focused: 为true时表示此View获取焦点,否则为失去焦点。
direction: 当前焦点移动的方向,可以为上,下,左,右,前向或是后向。
previouslyFocusedRect: 不为null时表示前一个获取焦点UI控件(View整体)的矩形区域大小。
对于本例来说,只有FOCUS_LEFT 和 FOCUS_RIGHT 会被执行到。 InternalSelectionFocus 从左到右并排显示3个InternalSelectionView的示例。 “左”,“右”键可以在左,中,右三个InternalSelectionView 来回移动UI焦点。 “上”,“下”就
补充:移动开发 , Android ,