Android ApiDemos示例解析(118):Views->Focus->4. Internal Selection

使用方向键或是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 显示 矩形,并以高亮(红色)显示当前选中的矩形。否则以黑色显示.

@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 当前选中的矩形。

@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 应正确设置选中区域矩形的大小:

 

@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移动行为。

@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焦点。 “上”,“下”就可以在当前获取UI焦点的一个InternalSelectionView对象上下选择一个矩形。

看看“左”,“右”键移动UI焦点时,下一个获取焦点的InternalSelectionView 中哪个矩形会被选中:

if (previouslyFocusedRect != null) {
 int y = previouslyFocusedRect.top
 + (previouslyFocusedRect.height() / 2);
 int yPerRow = getHeight() / mNumRows;
 mSelectedRow = y / yPerRow;
}

由于三个View的顶部和底部对齐 ,也就是previouslyFocusedRect 的top 和bottom 对于当前选中哪个View都是一样的,因此算出来的mSelectuedRow 都一样,对应本例都为3. 因此使用”左”,”右” 移动UI焦点时,下一个获取焦点的InternalSelectionView 总是首先选中序号为3的矩形。



 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值