我有一项任务,要跳过并禁用listview中的特定列表。但在做了一些研究之后,所有人都建议采用与here中相同的解决方案:
if(listview.getChildAt(selectedPosition).isEnabled())
{
listview.getChildAt(selectedPosition).setEnabled(false);
}
并且还有一些建议如下here中的方法。
我想问的是,甚至可以在不使用OnClickListener或任何Listener的情况下禁用和跳过listview中的特定列表项?因为我是一个Android电视开发人员,所有访问都使用远程控制,意味着KeyEvent。
所以例如,在listview的第二个列表中,我可以在A和B之间切换。每当我选择A时,listview的第一个列表需要禁用,每当我选择B时,listview的第三个列表需要禁用。所以这些是基本的想法。
MenuView.java
public class MenuView extends FrameLayout {
public static final int PAGE_INDEX_MIN = 1;
private int mPageIndexMax; //Determined after firmware series identified
private final LogUtility mLog = new LogUtility();
private View mBaseView;
private TextView mPublicModeTitle;
private ListView mItemListView;
private MenuPageAdapter mPageAdapter = null;
private Range<Integer> mPageRange;
private PageGenerator mPageGenerator;
private int mPageIndex = -1;
private int mItemCounter = 0;
private int mVolumeFixedState;
private static final int POUF_MENU_PAGE = 1;
private static final int POUF_ITEM_VOLUME_MAXIMUM = 0;
private static final int POUF_ITEM_VOLUME_FIXED = 1;
private static final int POUF_ITEM_INPUT_MODE_START = 3;
private static final int POUF_ITEM_RESET = 7;
private static final int POUF_ITEM_EXECUTE = 8;
private static final int POUF_VOLUME_FIXED_FIXED = 0;
private static final int POUF_VOLUME_FIXED_VARIABLE = 1;
/**
* States
*/
private boolean mCursorLocked = false;
private boolean mSelectLocked = false;
private boolean mApplyLocked = false;
/**
* Listener to catch extra keys
*/
private ExtraKeyListener mExtraKeyListener = new ExtraKeyListener() {
@Override
public boolean onKey(ExtraKey extraKey, String deviceName) {
View focusedView = findFocus();
if (focusedView == null) {
return false;
}
MenuItemInterface menuItem = (MenuItemInterface)focusedView.getTag(R.id.menu_base);
if (menuItem == null) {
// focused item is not menu item.
return false;
}
switch (extraKey) {
case KEYCODE_VOLUME_UP:
if (mSelectLocked == false) {
menuItem.select(1);
}
break;
case KEYCODE_VOLUME_DOWN:
if (mSelectLocked == false) {
menuItem.select(-1);
}
break;
}
return true;
}
};
public MenuView() {
super(InstanceManager.getService());
init();
}
/**
* set page to show
* @param index page index
* @return true on success.
*/
public boolean setPage(int index) {
TvKeyReceiver tvKeyReceiver = TvKeyReceiver.getInstance();
tvKeyReceiver.register();
tvKeyReceiver.addListener(mExtraKeyListener);
final int nextPageIndex = index;
final int delayMs = 100;
if (!mPageRange.contains(nextPageIndex)) {
return false;
}
if (mPageAdapter != null) {
mPageAdapter.destroy();
}
//TODO: repeating post is not good.
lockCursor(true);
lockSelect(true);
lockApply(true);
this.postDelayed(new Runnable() {
@Override
public void run() {
if (mPageAdapter != null && mPageAdapter.isDestroyFinished() == false) {
MenuView.this.postDelayed(this, delayMs);
return;
}
mPageIndex = nextPageIndex;
mPageAdapter = mPageGenerator.generate(mPageIndex);
mItemListView.setAdapter(mPageAdapter);
mItemCounter = POUF_ITEM_VOLUME_MAXIMUM;
updatePageViewText();
lockCursor(false);
lockSelect(false);
lockApply(false);
}
}, delayMs);
return true;
}
public void lockCursor(boolean enable) {
mCursorLocked = enable;
}
public void lockSelect(boolean enable) {
mSelectLocked = enable;
}
public void lockApply(boolean enable) {
mApplyLocked = enable;
}
/**
* Get busy status
* @return
*/
public boolean isBusy() {
if (mPageAdapter == null) {
return true;
}
if (mPageAdapter.areAnyItemsBusy()) {
return true;
}
return false;
}
@Override
protected void onAttachedToWindow() {
post(new Runnable() {
@Override
public void run() {
//Avoid no cursor issue in touch mode.
if (isInTouchMode()) {
int keyCode = KeyEvent.KEYCODE_TAB; // KeyEvent.KEYCODE_DPAD_RIGHT;
injectKey(keyCode); // force to exit touch mode.
}
setPage(mPageIndex);
}
});
super.onAttachedToWindow();
}
@Override
protected void onDetachedFromWindow() {
if (mPageAdapter != null) {
mPageAdapter.destroy();
mItemListView.setAdapter(null);
mPageAdapter = null;
}
//TODO: how handle mPageAdapter.isDestroyFinished()?
super.onDetachedFromWindow();
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
mVolumeFixedState = mPageGenerator.getVolumeFixedState();
if (handleFocusOperation(event) ||
handleItemOperation(event) ||
handleOtherOperation(event)) {
return true;
}
return super.dispatchKeyEvent(event);
}
private void updatePageViewText() {
final Typeface typeface = Typeface.createFromFile("LCFONT_LATIN");
mPublicModeTitle.setText("Public Mode");
mPublicModeTitle.setTypeface(typeface);
mVolumeFixedState = mPageGenerator.getVolumeFixedState();
if (mVolumeFixedState == POUF_VOLUME_FIXED_FIXED) {
mItemListView.setSelectionFromTop(POUF_ITEM_VOLUME_FIXED, 0);
mItemCounter = POUF_ITEM_VOLUME_FIXED;
}
}
/**
* initialize. called from constructor.
*/
private void init() {
LayoutInflater inflater = LayoutInflater.from(getContext());
mBaseView = inflater.inflate(R.layout.menu_base, this, false);
addView(mBaseView);
mPublicModeTitle = (TextView)findViewById(R.id.menu_title);
mItemListView = (ListView)findViewById(R.id.menu_item_list);
mItemListView.setItemsCanFocus(true);
mPageGenerator = new PageGeneratePouf(mItemListView, this);
mPageIndexMax = mPageGenerator.getNumberOfPages();
mPageRange = new Range<Integer>(PAGE_INDEX_MIN, mPageIndexMax);
mPageIndex = POUF_MENU_PAGE;
mItemCounter = POUF_ITEM_VOLUME_MAXIMUM;
// avoid showing dummy string in a moment.
updatePageViewText();
}
/**
* called from dispatchKeyEvent
*/
private boolean handleFocusOperation(KeyEvent event) {
boolean handled = true;
View focusedView = findFocus();
if (focusedView == null) {
mLog.d("currently no focus");
if (mPageAdapter != null) {
View view = mPageAdapter.getView(0, null, mItemListView);
if (view != null) {
view.requestFocus();
}
}
return true;
}
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_CHANNEL_DOWN: // next item
if (event.getAction() == KeyEvent.ACTION_DOWN && mCursorLocked == false) {
mLog.d("next item");
if ((mItemCounter == POUF_ITEM_VOLUME_FIXED) && (mVolumeFixedState == POUF_VOLUME_FIXED_VARIABLE)) {
setFocusDown();
}
setFocusDown();
}
break;
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_CHANNEL_UP: // previous item
if (event.getAction() == KeyEvent.ACTION_DOWN && mCursorLocked == false) {
mLog.d("previous item");
if ((mItemCounter == POUF_ITEM_VOLUME_FIXED) && (mVolumeFixedState == POUF_VOLUME_FIXED_FIXED)) {
break;
} else {
if ((mItemCounter == POUF_ITEM_INPUT_MODE_START) && (mVolumeFixedState == POUF_VOLUME_FIXED_VARIABLE)){
setFocusUp();
}
setFocusUp();
}
}
break;
default:
handled = false;
break;
}
return handled;
}
/**
* called from dispatchKeyEvent
*/
private boolean handleItemOperation(KeyEvent event) {
boolean handled = true;
View focusedView = findFocus();
if (focusedView == null) {
return false;
}
MenuItemInterface menuItem = (MenuItemInterface)focusedView.getTag(R.id.menu_base);
if (menuItem == null) {
// focused item is not menu item.
return false;
}
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_CENTER:
if (event.getAction() == KeyEvent.ACTION_DOWN && mApplyLocked == false) {
mLog.d("apply");
if (mItemCounter == POUF_ITEM_RESET) {
menuItem.apply();
setPage(PAGE_INDEX_MIN);
} else if (mItemCounter == POUF_ITEM_EXECUTE) {
menuItem.apply();
MenuWindow.getInstance().close();
}
}
break;
case KeyEvent.KEYCODE_VOLUME_UP:
if (event.getAction() == KeyEvent.ACTION_DOWN && mSelectLocked == false) {
mLog.d("value1 +1");
menuItem.select(1);
}
break;
case KeyEvent.KEYCODE_VOLUME_DOWN:
if (event.getAction() == KeyEvent.ACTION_DOWN && mSelectLocked == false) {
mLog.d("value1 -1");
menuItem.select(-1);
}
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (event.getAction() == KeyEvent.ACTION_DOWN && mSelectLocked == false) {
mLog.d("value2 +1");
menuItem.select(1);
}
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
if (event.getAction() == KeyEvent.ACTION_DOWN && mSelectLocked == false) {
mLog.d("value2 -1");
menuItem.select(-1);
}
break;
default:
handled = false;
break;
}
return handled;
}
/**
* called from dispatchKeyEvent
*/
private boolean handleOtherOperation(KeyEvent event) {
boolean handled = true;
switch (event.getKeyCode()) {
/* case KeyEvent.KEYCODE_Q: // quit
if (event.getAction() == KeyEvent.ACTION_DOWN) {
mLog.i("quit");
InstanceManager.getMenu().close();
}
break;
*/ default:
handled = false;
break;
}
return handled;
}
/**
* Inject key event using InputManager.
* @param keyCode
*/
private void injectKey(int keyCode) {
int source = InputDevice.SOURCE_KEYBOARD;
int keyboard = KeyCharacterMap.VIRTUAL_KEYBOARD;
long now = SystemClock.uptimeMillis();
KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0, keyboard, 0, 0, source);
KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0, keyboard, 0, 0, source);
InputManager inputManager = (InputManager)InstanceManager.getService().getSystemService(Context.INPUT_SERVICE);
inputManager.injectInputEvent(down, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
inputManager.injectInputEvent(up, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
private void setFocusDown() {
View newfocusedView = findFocus();
View newView = newfocusedView.focusSearch(FOCUS_DOWN);
if (newView != null) {
newView.requestFocus(FOCUS_DOWN);
mItemCounter += 1;
}
}
private void setFocusUp() {
View newfocusedView = findFocus();
View newView = newfocusedView.focusSearch(FOCUS_UP);
if (newView != null) {
newView.requestFocus(FOCUS_UP);
mItemCounter -= 1;
}
}
}
MenuPageAdapter.java
class MenuPageAdapter extends BaseAdapter {
private MenuItemInterface[] mMenuItems;
public MenuPageAdapter(MenuItemInterface[] menuItems) {
this(Arrays.asList(menuItems));
}
public MenuPageAdapter(Collection<MenuItemInterface> menuItems) {
mMenuItems = new MenuItemInterface[menuItems.size()];
menuItems.toArray(mMenuItems);
}
/**
* Start to destroy items.
* @return
*/
public boolean destroy() {
boolean result = true;
for (MenuItemInterface i: mMenuItems) {
result &= i.destroy();
}
return result;
}
/**
* @return true if all items are already destroyed.
*/
public boolean isDestroyFinished() {
for (MenuItemInterface i: mMenuItems) {
if (i.isDestroyFinished() == false) {
return false;
}
}
return true;
}
@Override
public int getCount() {
return mMenuItems.length;
}
@Override
public Object getItem(int position) {
return mMenuItems[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return mMenuItems[position].getView();
}
@Override
public int getViewTypeCount() {
return 1; // TODO: should return 0? (because getItemViewType always return IGNORE_ITEM_VIEW_TYPE)
}
@Override
public int getItemViewType(int position) {
return BaseAdapter.IGNORE_ITEM_VIEW_TYPE;
}
/**
* Get busy status.
* @return
*/
public boolean areAnyItemsBusy() {
for (MenuItemInterface mi: mMenuItems) {
if (mi.isBusy()) {
return true;
}
}
return false;
}
}