0

I have a task, to skip and disable particular list in listview. But after do some research, all suggest the same solution which is like below as in here:

if(listview.getChildAt(selectedPosition).isEnabled())
{
    listview.getChildAt(selectedPosition).setEnabled(false);
}

and also some suggestion is below method like in here also.

what i want to ask it, is it even possible to disable and skip particular list item in listview without using OnClickListener or any Listener? since im a android TV developer, all access are using remote control, means KeyEvent.

so for example, at the second list of listview, i can switch between A and B. whenever i select A, first list of listview need to disable, and whenever i select B, third list of listview need to disable. so these are the basic idea.

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;
    }
}
Community
  • 1
  • 1
squall leonhart
  • 301
  • 1
  • 5
  • 16
  • When you say `particular list in listview` do you mean `item in listview` ? You question is not clear to me. I don't understand what you are trying to achieve. Post your code and explain it better please – Gokhan Arik Jun 20 '16 at 03:35
  • yes. what i want to do is just like this [example](http://www.android-examples.com/disable-particular-item-in-listview-android-programmatically/) – squall leonhart Jun 20 '16 at 03:39
  • sir, i already edit my question, and post the code. in this code, my friend already done the skip. but not the gray off. but i think there is better way than this. – squall leonhart Jun 20 '16 at 03:42
  • If I understand correctly, you want to disable an item at a specific position without getting position from a click event. `ListView` has `getChildAt(i)` method. You can use `mListView.getChildAt(i).setEnabled(true/false)` – Gokhan Arik Jun 20 '16 at 03:48
  • 1
    Why would you need any event to enable or disable an item? Why don't you just track enabled/disabled state in your model and bind it to the `Views` accordingly? – Xaver Kapeller Jun 20 '16 at 03:49
  • @Gokhan Arik I already try using `getChildAt()`, but this method can only be used by `ArrayAdapter` right? while this listview is using `MenuPageAdapter`. so I think different adapter have different API right? – squall leonhart Jun 20 '16 at 03:57
  • @GokhanArik You should never modify a child `View` in a `ListView` or `RecyclerView` outside outside of its `Adapter` unless in very specific circumstances. Also what you suggest won't work. You have to track and apply enabled/disabled state from the model otherwise view recycling will cause problems. – Xaver Kapeller Jun 20 '16 at 03:59
  • @XaverKapeller this code actually not done by me. since the real PIC already left, so im charge this code. and if i'm about to change the structure, it take a lot of things to consider since this code is only a piece of code from the app that i working for. – squall leonhart Jun 20 '16 at 04:01
  • Also I feel compelled to point out that the op should consider switching to `RecyclerView` instead of a `ListView`. `RecyclerView` is much better and fixes a lot of problems with `ListView`. – Xaver Kapeller Jun 20 '16 at 04:02
  • @XaverKapeller I know that I just wanted to give an answer to his specific question. The recommended way is to bind it in view holder. – Gokhan Arik Jun 20 '16 at 04:03
  • @squallleonhart The method I told you is in ListView not adapter. Yes it would be better for you to switch to RecyclerView. You will have advantage of ViewHolder. You can have a boolean flag on your object in your list and use itemView.setEnabled(i) method to enable disable them. If you need to make changes on disabled/enabled state, you update your list and call notifyDatasetChanged() – Gokhan Arik Jun 20 '16 at 04:05
  • Would you really be changing that much code? The `Adapter` of your `ListView` has to be backed by some kind of items, these items have to track the state of each `View`. This can't work any other way. So go to these items and add a boolean flag for enabled/disabled state and then modify your `Adapter` to bind that to the `Views`. That's all you have to do. – Xaver Kapeller Jun 20 '16 at 04:05
  • Use RecyclerView with different type and just disable item which you want – Amir Jun 20 '16 at 04:32
  • @GokhanArik i try to use `getChildAt()` method like below: `if (mVolumeFixedState == POUF_VOLUME_FIXED_VARIABLE) { mItemListView.getChildAt(0).setEnabled(false); } else { mItemListView.getChildAt(2).setEnabled(false); }` and put it under `updatePageViewText()`, but there is a NullPointerException error - `Attempt to invoke virtual method 'void android.view.View.setEnabled(boolean)' on a null object reference`. what kind of null check that i need to add to fix this error? – squall leonhart Jun 20 '16 at 06:01
  • How many items do you have in your adapter? – Gokhan Arik Jun 20 '16 at 06:07
  • @GokhanArik hi, sorry for the late. you mean items in my listview? if so then there are 8 items. – squall leonhart Jun 20 '16 at 07:26
  • 1
    Don't use `getChildAt()`, that can't work. Doing that will just cause problems. If not right now, then later. Just try scrolling through the list after doing that and you will see what I mean. – Xaver Kapeller Jun 20 '16 at 07:46
  • I agree with Xaver – Gokhan Arik Jun 20 '16 at 15:46
  • Hi, i try to use method such as in the answer [here](http://stackoverflow.com/questions/2183610/android-how-to-disable-list-items-on-list-creation), by using `areAllItemsEnabled()` and `isEnabled()`, but i have the problem where the line separetor instead is gone, just like in [here](http://stackoverflow.com/questions/5375138/disappearing-divider-in-listview-when-arrayadapter-isenabled-returns-false). and after reading some research, it seems this method is not working correctly for Android 5. I wonder why. i edit my question, by adding the `MenuPageAdapter.java`. – squall leonhart Jun 21 '16 at 06:51

0 Answers0