Как переключить изображение кнопки с включенного на выключенное и наоборот при нажатии?

Я пытался переключить состояние моих кнопок с включенного на выключенное и наоборот, добавив изображение для включения и добавив изображение для выключенного состояния. Я пробовал через xml, однако мне удалось временно переключить его при нажатии (с помощью нажатия/фокуса и т. д.). Вот код для того же:

фрагмент_юстин:

<RelativeLayout
        android:id="@+id/top_bar_container"
        android:layout_width="match_parent"
        android:layout_height="48.5dp"
        android:layout_alignParentTop="true"
        android:background="@color/background_action_bar"
        android:orientation="horizontal" >

        <ImageButton
            android:id="@+id/menu_button"
            android:layout_width="30dp"
            android:layout_height="48.5dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:background="@android:color/transparent"
            android:paddingRight="24dp"
            android:src="@drawable/overflow_btn" />

        <com.justin.abc.FontTextView
            android:id="@+id/most_recent_text"
            android:layout_width="wrap_content"
            android:layout_height="48.5dp"
            android:layout_marginLeft="11dp"
            android:layout_marginRight="2dp"
            android:textColor="@color/white"
            foo:customFont="Cabin-Bold.ttf"
            android:layout_alignParentLeft="true"
            android:textSize="18sp"
            android:gravity="center_vertical"
            android:text="@string/most_recent"/>

    </RelativeLayout>

Сосредоточившись только на части кнопки изображения, вы увидите overflow_btn. Теперь overflow_btn — это класс, вызываемый в drawable следующим образом:

кнопка_переполнения:

 <?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
    android:state_enabled="false"
    android:drawable="@drawable/overflow_pressed" />
<item
    android:state_pressed="true"
    android:state_enabled="true"
    android:drawable="@drawable/overflow_pressed" />
<item
    android:state_focused="true"
    android:state_enabled="true"
    android:drawable="@drawable/overflow_pressed" />
<item
    android:state_enabled="true"
    android:drawable="@drawable/overflow" />
</selector>

При использовании приведенного выше кода он временно переключает состояния кнопки только при нажатии (например, она мигает на overflow_pressed) и возвращается обратно к переполнению. Я считаю, что для этого могут потребоваться некоторые изменения в коде Java, поэтому здесь соответствующий класс Java:

@Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_justin, container, false);
        createMenus() ;
        setOnclickListeners(view);

        mAdapter = new CursorAdapter(getActivity(), null, 0);
        final ListView list = (ListView) view.findViewById(R.id.justin_list);
        list.setAdapter(mAdapter);
        list.setOnItemLongClickListener(this);
        list.setOnTouchListener(this);
        list.setOnItemClickListener(this);

        LayoutUtils.showLoading(view, R.id.justin_list);
        return view;
    }

    private void setOnclickListeners(final View view){
        final ImageButton button = (ImageButton) view.findViewById(R.id.menu_button);
        button.setOnClickListener(this);
    }

    private void createMenus() {
        mPreferenceMenuItems.add(PreferenceMenuItems.JUSTIN_PREFERENCES);
        mPreferencesMenuHelper = new MenuHelper(getActivity(), mPreferenceMenuItems,this);

        mDeleteMenuItems.add(DeleteMenuItems.DELETE_JUSTIN);
        mDeleteMenuHelper = new MenuHelper(getActivity(), mDeleteMenuItems,this);
    }

    @Override
    public void onResume() {
        super.onResume();
        final MainActivity activity = (MainActivity) getActivity();
        activity.updateActionBarTitle();
        final IntentFilter filter = new IntentFilter();
        activity.getApplicationContext().registerReceiver(mReceiver, filter);
    }

    @Override
    public void onPause() {
        getActivity().getApplicationContext().unregisterReceiver(mReceiver);
        super.onPause();
    }

    @Override
    public void onCursorLoaded(final Uri uri, final Cursor cursor) {
        if (cursor.getCount() > 0) {
            mAdapter.swapCursor(cursor);
            showResults(uri);
        } else {
            if (!isOperationExecuting()) {
                showNoResults(uri);
            }
        }
    }


    @Override
    public void onMenuItemClicked(final int position) {
        if (isPreferences) {
            switch (position) {
                case PreferenceMenuItems.JUSTIN_PREFERENCES_POSITION:
                    PreferencesActivity.newInstance(getActivity());
                    break;
                default:
                    break;
            }
            mPreferencesMenuHelper.hideMenu();
        } else {
            switch (position) {
                case DeleteMenuItems.DELETE_POSITION:
                    final DialogFragment dialog = new DeleteFromDialogFragment();
                    final Bundle bundle = new Bundle();
                    bundle.putString(JUSTIN_ID, mJustinID);
                    dialog.setArguments(bundle);
                    dialog.show(getFragmentManager(), DELETE_FROM_JUSTIN );
                    break;
                default:
                    break;
            }
            mDeleteMenuHelper.hideMenu();
        }
    }

    @Override
    public void onClick(final View view) {
        switch (view.getId()) {
            case R.id.justin_menu_button:
                final Activity activity = getActivity();
                final int actionBarHeight = activity.findViewById(R.id.title_main_container).getHeight();
                final int menuBarHeight = activity.findViewById(R.id.justin_top_bar_container).getHeight();
                mPreferencesMenuHelper.showMenu(actionBarHeight + menuBarHeight, Gravity.RIGHT, R.style.MenuDialogAnimation);
                isPreferences = true;

                break;
            default:
                break;
        }
    }

    @Override
    public void showResults(final Uri uri) {
        if (mIsAnimating) {
            mShouldShowResult = true;
        } else {
            LayoutUtils.showResults(getView(), R.id.justin_list);
            mShouldShowResult = false;
        }
    }

    @Override
    public void showNoResults(final Uri uri) {
        if (mIsAnimating) {
            mShouldShowNoResult  = true;
        } else {
            LayoutUtils.showNoResult(getView(), R.id.justin_list, getResources().getString(R.string.no_result));
            mShouldShowNoResult = false;
        }
    }

    @Override
    public void onOperationStarted(final Uri uri) {
        LayoutUtils.showLoading(getView(), R.id.justin_list);
    }

    @Override
    public boolean onItemLongClick(final AdapterView<?> adapter, final View view, final int position, final long id) {
        isPreferences = false;
        final Activity activity = getActivity();
        final int actionBarHeight = activity.findViewById(R.id.title_main_container).getHeight();
        final int menuBarHeight = activity.findViewById(R.id.justin_top_bar_container).getHeight();
        mDeleteMenuHelper.showMenu(mYValue + actionBarHeight + menuBarHeight, Gravity.CENTER, R.style.MenuDialogAnimation);

        final Cursor cursor = (Cursor) mAdapter.getItem(position);
        mJustinID = cursor.getString(cursor.getColumnIndex(Justin.Columns.ID));

        return false;
    }

    @Override
    public boolean onTouch(final View v, final MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN){
            mYValue = (int)event.getY();
        }

        return false;
    }

    public void restartLoader(){
        getContentLoader().restartLoader();
    }

    @Override
    public void onItemClick(final AdapterView<?> adapter, final View view, final int position, final long id) {
        final Cursor cursor = (Cursor) mAdapter.getItem(position);
        if (!NetworkUtils.isOnline() && ContentProvider.isStoryEmty(cursor)) {
            final DialogFragment dialog = new CheckOfflineAccessDialogFragment();
            dialog.show(getFragmentManager(), OFFLINE_ACCESS);
            return;
        }

        final String documentSource = cursor.getString(cursor.getColumnIndex(Justin.Columns.SOURCE));
        final ArticlePagerFragment ArticlePagerFragment = ArticlePagerFragment.newInstance(getFragmentManager(), position, documentSource, false);
        ArticlePagerFragment.setFragment(this);

    }

    public static String getArticleID(final Cursor cursor) {
        final String documentLink = cursor.getString(cursor.getColumnIndex(Justin.Columns.DOCUMENT_LINK));
        final String documentType = cursor.getString(cursor.getColumnIndex(Justin.Columns.TYPE));
        final String source = cursor.getString(cursor.getColumnIndex(Justin.Columns.SOURCE));
        String articleID = "";
        if (source.equalsIgnoreCase(Justin.NEWS_SOURCE_VALUE) && documentType.equalsIgnoreCase(Justin.TEXT_TYPE)) {
            articleID = documentLink.substring(documentLink.lastIndexOf("storyId=")+8);
        }
        return articleID;
    }

Есть идеи, как сделать то же самое?

МенюПомощник:

public class MenuHelper implements OnItemClickListener{

    private final Dialog mMenu;
    private final OnMenuItemClickedListener mMenuItemListener;
    private final ArrayAdapter<String> mAdapter;
    private final int MENU_ITEM_HEIGHT = 40; // Defined in res/layout/menu_item.xml

    private List<Boolean> enabledStates;

    public MenuHelper(final Context context, final List<String> menuItems, final OnMenuItemClickedListener menuItemListener) {
        mMenu = new Dialog(context);
        mMenu.requestWindowFeature(Window.FEATURE_NO_TITLE);
        mMenu.setContentView(R.layout.menu_container);
        enabledStates = new ArrayList<Boolean>(menuItems.size());
        for(int i = 0; i < menuItems.size(); i++) {
            enabledStates.add(true);
        }

        final ListView menuList = (ListView) mMenu.findViewById(R.id.menu_list);
        mAdapter = new ArrayAdapter<String>(context, R.layout.menu_item, menuItems) {
            @Override
            public boolean isEnabled(int position) {
                return enabledStates.get(position);
            }

            @Override
            public boolean areAllItemsEnabled() {
                return false;
            }

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View view = super.getView(position, convertView, parent);
                if(enabledStates.get(position)) {
                    ((TextView) view).setTextColor(Application.getAppResources().getColor(R.color.white));
                } else {
                    ((TextView) view).setTextColor(Application.getAppResources().getColor(R.color.disabled_gray));
                }
                if (convertView == null) {
                    convertView = super.getView(position, convertView, parent);
                }

                // check for odd or even to set alternate colors to the row background
                if (position % 2 == 0) {
                    convertView.setBackgroundResource(R.drawable.oddcellcolor);
                } else {
                    convertView.setBackgroundResource(R.drawable.evencellcolor);
                }
                return convertView;
                //return view;
            }
        };
        menuList.setOnItemClickListener(this);
        menuList.setAdapter(mAdapter);
        mMenuItemListener = menuItemListener;
    }

    public void showMenu(final int yPosition, final int horizontalGravity) {
        showMenu(yPosition, horizontalGravity, R.style.MenuDialogAnimation);
    }

    public void setEnabled(int position, boolean isEnabled) {
        enabledStates.set(position, isEnabled);
        mAdapter.notifyDataSetChanged();
    }

    public void setEnabledAll(boolean isEnabled) {
        for(int ii = 0; ii < enabledStates.size(); ii++) {
            enabledStates.set(ii, isEnabled);
        }
        mAdapter.notifyDataSetChanged();
    }

    public int getMenuHeight() {
        if (mMenu != null) {
            return (int) (mAdapter.getCount() * MENU_ITEM_HEIGHT  / Application.getAppResources().getDisplayMetrics().density);
        } else {
            return -1;
        }
    }

    public void showMenu(final float yPosition, final int horizontalGravity, final int animation) {
        final Window window = mMenu.getWindow();
        window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        if (horizontalGravity != Gravity.CENTER) {
            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        }
        final WindowManager.LayoutParams params = window.getAttributes();
        params.gravity = Gravity.TOP | horizontalGravity;
        params.y = Math.round(yPosition);
        params.windowAnimations = animation;
        window.setAttributes(params);
        mMenu.show();
    }

    public void hideMenu() {
        mMenu.hide();
    }

    @Override
    public void onItemClick(final AdapterView<?> adapter, final View view, final int position, final long parent) {
        mMenuItemListener.onMenuItemClicked(position);
    }


}

Спасибо! Джастин


person Community    schedule 24.07.2013    source источник


Ответы (5)


Я согласен с @Chronos, это больше похоже на ToggleButton с два состояния. Будьте проще, вот моя, которую вы можете использовать в качестве примера. Код не нужен, только xml.

вот xml для моего макета:

<ToggleButton
        android:id="@+id/btnHeadache"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_centerHorizontal="true"
        android:background="@drawable/headache_button"
        android:paddingTop="25sp"
        android:text="@string/headache"
        android:textOn=""
        android:textOff="" />

Теперь вот xml для разных состояний, который, конечно же, находится в моей папке с изображениями. Это называется head_button.xml, если это неясно выше:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/check"  android:state_checked="true"/> <!-- currently pressed turning the toggle on -->
    <item android:drawable="@drawable/headache" android:state_checked="false" /> <!-- currently pressed turning the toggle off   -->
</selector>
person jcaruso    schedule 31.07.2013

Если я правильно понимаю, вам нужна ToggleButton , кнопка с двумя состояниями.

И используйте селектор, подобный этому:

<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/btn_normal" android:state_checked="false"/>
    <item android:drawable="@drawable/btn_pressed" android:state_checked="true"/>

</selector>
person Chronos    schedule 26.07.2013

Это больше похоже на то, что вы должны использовать CheckBox. Обычные кнопки не имеют состояния «включено», они просто нажаты и сфокусированы. С флажком вам нужно будет использовать android:state_checked="true". Щелчок по флажку переключится в отмеченное состояние, щелчок по нему снова вернет его в состояние по умолчанию (не отмечен).

Старайтесь не добавлять лишний java-код, пока не будете уверены, что не можете что-то сделать с XML.

person Coeffect    schedule 25.07.2013
comment
не то, что я ищу. Мне нужно переключить изображение на другое, что определенно возможно и не имеет ничего общего с флажком - person ; 25.07.2013
comment
у вас есть какие-либо идеи об этой проблеме: stackoverflow.com/questions/18382510/ - person ; 26.08.2013

Вы можете сделать это в коде, используя:

// Declare button
// Set its original background image
button.setBackground(getResources().getDrawable(R.drawable.original_button_image));

button.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {

        // Choose whichever image for pressed state
        v.setBackground(getResources().getDrawable(R.drawable.button_is_pressed)); 

        new Handler().postDelayed(new Runnable() {

            public void run() {

                v.setBackground(getResources().getDrawable(R.drawable.original_button_image));

                // Button Click Code Here
            }

        }, 100L);    // Change this value to whatever is suitable

    }

});

Изменить 1:

<ImageButton
        android:id="@+id/menu_button"
        android:layout_width="30dp"
        android:layout_height="48.5dp"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:background="@android:color/transparent"
        android:src="@drawable/testdrawable"
        android:paddingRight="24dp" />

Поскольку кнопка имеет только два состояния, попробуйте testdrawable вместо того, которое вы указали в своем вопросе:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item 
        android:state_selected="true" 
        android:drawable="@drawable/overflow_pressed" />
    <item 
        android:drawable="@drawable/overflow" />
</selector>

Измените свой onClick(View) на:

@Override
public void onClick(final View view) {
    switch (view.getId()) {
        case R.id.justin_menu_button:

            if (button.isSelected()) {
                button.setSelected(false);
                isPreferences = false;
                mPreferencesMenuHelper.hideMenu();
                Log.i("ImageButtonCheck", "Button is not selected anymore");
            } else {
                button.setSelected(true);
                final Activity activity = getActivity();
                final int actionBarHeight = activity.findViewById(R.id.title_main_container).getHeight();
                final int menuBarHeight = activity.findViewById(R.id.justin_top_bar_container).getHeight();
                mPreferencesMenuHelper.showMenu(actionBarHeight + menuBarHeight, Gravity.RIGHT, R.style.MenuDialogAnimation);
                isPreferences = true;
                Log.i("ImageButtonCheck", "Button is in selected state");
            }

            break;
        default:
            break;
    }
}

Измените onMenuItemClicked(int) на:

@Override
public void onMenuItemClicked(final int position) {
    if (isPreferences) {
        switch (position) {
            case PreferenceMenuItems.JUSTIN_PREFERENCES_POSITION:
                PreferencesActivity.newInstance(getActivity());
                break;
            default:
                break;
        }
        isPreferences = false;
        button.setSelected(false);
        mPreferencesMenuHelper.hideMenu();
        Log.i("ImageButtonCheck", "Button is not in a selected state because of a menu item click");
    } else {
        switch (position) {
            case DeleteMenuItems.DELETE_POSITION:
                final DialogFragment dialog = new DeleteFromDialogFragment();
                final Bundle bundle = new Bundle();
                bundle.putString(JUSTIN_ID, mJustinID);
                dialog.setArguments(bundle);
                dialog.show(getFragmentManager(), DELETE_FROM_JUSTIN );
                break;
            default:
                break;
        }
        mDeleteMenuHelper.hideMenu();
    }
}

Я думаю, что проблема здесь в том, что при первом нажатии кнопки достигается выбранное состояние и отображается меню. Но повторный щелчок по кнопке во время отображения меню не вызывает метод onClick(View). Я включил 3 оператора журнала в приведенный выше код. Сообщите мне о выводе, который вы видите в logcat, когда вы нажимаете кнопку один раз, чтобы отобразить меню, и снова щелкаете меню, чтобы скрыть его. Результатом этих двух щелчков должно быть "Button is in selected state" и "Button is not selected anymore".

Редактировать 2:

Включите MenuHelper в качестве внутреннего класса в свой класс активности:

public class MenuHelper implements OnItemClickListener, Dialog.OnDismissListener {

    private final Dialog mMenu;
    private final OnMenuItemClickedListener mMenuItemListener;
    private final ArrayAdapter<String> mAdapter;
    private final int MENU_ITEM_HEIGHT = 40; // Defined in res/layout/menu_item.xml

    private List<Boolean> enabledStates;

    public MenuHelper(final Context context, final List<String> menuItems, final OnMenuItemClickedListener menuItemListener) {
        mMenu = new Dialog(context);
        mMenu.requestWindowFeature(Window.FEATURE_NO_TITLE);
        mMenu.setContentView(R.layout.menu_container);
        mMenu.setOnDismissListener(this);  -------------------------> **add this**
        enabledStates = new ArrayList<Boolean>(menuItems.size());
        for(int i = 0; i < menuItems.size(); i++) {
            enabledStates.add(true);
        }

        final ListView menuList = (ListView) mMenu.findViewById(R.id.menu_list);
        mAdapter = new ArrayAdapter<String>(context, R.layout.menu_item, menuItems) {
            @Override
            public boolean isEnabled(int position) {
                return enabledStates.get(position);
            }

            @Override
            public boolean areAllItemsEnabled() {
                return false;
            }

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View view = super.getView(position, convertView, parent);
                if(enabledStates.get(position)) {
                    ((TextView) view).setTextColor(Application.getAppResources().getColor(R.color.white));
                } else {
                    ((TextView) view).setTextColor(Application.getAppResources().getColor(R.color.disabled_gray));
                }
                if (convertView == null) {
                    convertView = super.getView(position, convertView, parent);
                }

                // check for odd or even to set alternate colors to the row background
                if (position % 2 == 0) {
                    convertView.setBackgroundResource(R.drawable.oddcellcolor);
                } else {
                    convertView.setBackgroundResource(R.drawable.evencellcolor);
                }
                return convertView;
                //return view;
            }
        };
        menuList.setOnItemClickListener(this);
        menuList.setAdapter(mAdapter);
        mMenuItemListener = menuItemListener;
    }

    public void showMenu(final int yPosition, final int horizontalGravity) {
        showMenu(yPosition, horizontalGravity, R.style.MenuDialogAnimation);
    }

    public void setEnabled(int position, boolean isEnabled) {
        enabledStates.set(position, isEnabled);
        mAdapter.notifyDataSetChanged();
    }

    public void setEnabledAll(boolean isEnabled) {
        for(int ii = 0; ii < enabledStates.size(); ii++) {
            enabledStates.set(ii, isEnabled);
        }
        mAdapter.notifyDataSetChanged();
    }

    public int getMenuHeight() {
        if (mMenu != null) {
            return (int) (mAdapter.getCount() * MENU_ITEM_HEIGHT  / Application.getAppResources().getDisplayMetrics().density);
        } else {
            return -1;
        }
    }

    public void showMenu(final float yPosition, final int horizontalGravity, final int animation) {
        final Window window = mMenu.getWindow();
        window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        if (horizontalGravity != Gravity.CENTER) {
            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        }
        final WindowManager.LayoutParams params = window.getAttributes();
        params.gravity = Gravity.TOP | horizontalGravity;
        params.y = Math.round(yPosition);
        params.windowAnimations = animation;
        window.setAttributes(params);
        mMenu.show();
    }

    public void hideMenu() {
        mMenu.hide();
    }

    @Override
    public void onItemClick(final AdapterView<?> adapter, final View view, final int position, final long parent) {
        mMenuItemListener.onMenuItemClicked(position);
    }

    @Override
    public void onDismiss(DialogInterface arg0) {
        button.setSelected(false);
    }

}
person Vikram    schedule 25.07.2013
comment
Я сделал это, но теперь каждый раз, когда я нажимаю кнопку во второй раз, меню исчезает (как и ожидалось) и приложение вылетает. - person ; 29.07.2013
comment
@JusticeBauer Не могли бы вы поделиться кодом? Будет легче отлаживать, если он у меня есть на моей машине. - person Vikram; 31.07.2013
comment
не беспокойтесь, все получилось, спасибо за помощь, не могли бы вы взглянуть на этот вопрос: stackoverflow.com/questions/17956135/ и посмотрите, можете ли вы помочь решить эту проблему. - person ; 02.08.2013
comment
у вас есть какие-либо идеи об этой проблеме: stackoverflow.com/questions/18382510/ - person ; 26.08.2013

Если я вас правильно понял, вам нужна «Кнопка» с двумя состояниями, и нажатие на нее переключает между ними.

В этом случае это больше похоже на то, что вам нужно поведение «ToggleButton», «CompoundButton» или «Switch». Вы можете настроить их в xml, используя «android: state_checked» в соответствии с @Chronos.

person Neil Townsend    schedule 25.07.2013
comment
Это сработало для первого, однако, где я могу добавить view.setEnabled(true); , чтобы вернуться к исходному изображению при повторном нажатии - person ; 25.07.2013
comment
Итак, вы хотите, чтобы кнопка реагировала. Я подумаю и исправлю свой ответ на следующий день или около того. - person Neil Townsend; 25.07.2013
comment
хорошо, насколько я вижу, первый view.setEnabled(false); работает нормально, просто интересно, что мне нужно установить и где, чтобы он мог вернуться в исходное состояние при каждом нажатии - person ; 25.07.2013
comment
больше похоже на включение и выключение изображения - person ; 25.07.2013
comment
Любая подсказка о проблеме еще? - person ; 26.07.2013
comment
Мой ноутбук умер, и я отсутствую дома в течение десяти дней, но я добавлю больше в ответ, как только смогу, извините за задержку. - person Neil Townsend; 29.07.2013