메뉴 버튼이있는 장치에서 오버플로 메뉴를 사용하는 방법


159

나는 오버 플로우 메뉴에 액션 바의 이동 (작업 표시 줄이 아니라 메뉴 버튼에서 도달 한)에 맞지 않는 모든 메뉴 항목이하고 싶은 경우에도 장치 Menu (메뉴) 버튼이를 . 이것은 ActionBar의 레이아웃이 막대에 맞지 않기 때문에 사용자가 터치 (스크린) 상호 작용에서 버튼 기반 상호 작용으로 이동 해야하는 별도의 메뉴 목록으로 사용자를 던지는 것보다 훨씬 직관적 인 것처럼 보입니다.

에뮬레이터에서 "Hardware Back / Home Keys"값을 "no"로 설정하여이 효과를 얻을 수 있습니다. 메뉴 버튼이 있지만 실제로는 잘 작동하지 않는 실제 장치에 대한 코드 에서이 작업을 수행하는 방법을 찾았습니다. 누구든지 나를 도울 수 있습니까?

답변:


54

편집 : 물리적 메뉴 버튼의 상황에 응답하도록 수정되었습니다.

이것은 실제로 의도적으로 방지됩니다. 에 따르면 안드로이드 디자인 가이드의 호환성 섹션 ,

"... 작업 오버 플로우는 메뉴 하드웨어 키에서 사용할 수 있습니다. 결과 작업 팝업 ...이 화면 하단에 표시됩니다."

스크린 샷에서 물리적 메뉴 버튼이있는 전화기의 ActionBar에는 오버플로 메뉴가 없습니다. 이렇게하면 사용자에게 애매 모호함을 피할 수 있으며 기본적으로 정확히 동일한 메뉴를 열 수있는 두 개의 단추가 있습니다.

여러 기기에서 일관성 문제를 해결하려면 궁극적으로 모든 기기에서 일관되게 동작하는 것보다 앱이 동일한 기기의 다른 모든 앱과 일관되게 동작하는 것이 사용자 경험에 더 중요합니다.


1
Alexander-아니요, 모든 showAsAction 값과 여러 조합을 시도했지만 그 중 어느 것도 트릭을 수행하지 않습니다 (적어도 에뮬레이터에서). 메뉴 모음이 없는 장치 에뮬레이션 한 경우 작업 표시 줄의 오버플로 메뉴 만 나타납니다 . 세로 줄임표 있고 메뉴 버튼 이있는 장치에서 넘친 항목이 표시되도록하고 싶습니다 . 좀 더 명확하게하기 위해 내 질문을 편집했습니다.
PaulP

41
이 대화에 들어가서 토론 해 보자 : 나는 그것이 디자인에 의해 방지된다는 것을 안다 (디자인 지침을 읽음). 그러나 그것은 일종의 % $ / % # +라고 생각합니다. 예를 들어, 사용자가 Galaxy Nexus (-> w 오버플로)에서 Nexus One (w 4.0 /-> 오버플로 없음)으로 전환하고 있습니다. 사용자가 더 이상 메뉴 항목을 찾지 못할 것입니다. 이런 이유로 모든 장치에서 동일한 사용법을 원합니다. 그래서, 나는 paulp와 같은 문제로 끝납니다. 깨끗한 해결 방법이 없습니까?
Sprigg

10
저도 디자인 가이드를 먼저 읽었습니다. 나에게 이것은 지원 패키지에서 잘못된 디자인 선택이었습니다. 버튼에서 사용자를 멀리 전환하는 더 좋은 전략은 (객관적인 것입니까?) 중복을 만들고 기능을 화면과 버튼에 두는 것입니다. 이제는 버튼에 모든 메뉴 선택 사항이 표시되지 않고 작업 표시 줄에없는 항목 만 표시 되므로이 디자인은 작업 표시 줄로의 부드러운 전환을 지원하지 않으며 작업 표시 줄을 추가하기 전에 수행 한 작업을 수행하지 않습니다 ( 모든 메뉴 표시) 선택). 나는 당신이 옳고 간단한 해결 방법이 없다고 생각합니다.
PaulP 2019

18
Google은 새로운 Google + 앱에서이 문제를 해결합니다. 그것은 장치에 관계없이 오버플로 항목을 가지고 있습니다. 그러나 그들은 여전히 ​​개발자가 똑같은 조언을하지 못하고 제 지식에 대해 조언하지 않습니다.
Karl

10
솔직히 말해서, 너무 많은 사용자가 메뉴 하드 키를 사용하여 기대하지 않는 것을 보았습니다. 디자인에 전화기의 사용자에게 메뉴 옵션이 있음을 나타내는 화면 표시기가 없어야한다고하면 해당 디자인에 대한 정보가 부족한 것입니다.
랜스 나 넥크

323

이 작은 핵을 여기에서도 사용할 수 있습니다.

try {
    ViewConfiguration config = ViewConfiguration.get(this);
    Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
    if (menuKeyField != null) {
        menuKeyField.setAccessible(true);
        menuKeyField.setBoolean(config, false);
    }
} catch (Exception ignored) {
}

그것을 넣을 수있는 좋은 장소 onCreate는 귀하의 응용 프로그램 수업의 방법입니다.

앱이 오버플로 메뉴를 표시하도록 강제합니다. 메뉴 버튼은 여전히 ​​작동하지만 오른쪽 상단에 메뉴가 열립니다.

[편집] 현재 여러 번 등장한이 해킹은 ActionBarSherlock이 아니라 Android 3.0에 도입 된 기본 ActionBar에서만 작동합니다. 후자는 자체 내부 로직을 사용하여 오버플로 메뉴를 표시할지 여부를 결정합니다. ABS를 사용하는 경우 4.0 미만의 모든 플랫폼은 ABS에 의해 처리되므로 해당 논리가 적용됩니다. 해킹은 Android 4.0 이상이 설치된 모든 기기에서 계속 작동합니다 (메뉴 버튼이있는 태블릿이 없기 때문에 Android 3.x를 무시해도됩니다).

ABS에서 메뉴를 강제 실행하는 특수 ForceOverflow 테마가 있지만, 합병증으로 인해 이후 버전에서는 제거 될 예정 입니다.


4
소스 코드를 살펴 보았습니다. 문서화되지 않은 기능의 보물 숲 :) 그냥 그런 것들에 대해 실행 가능한 대체물이 있는지 확인하십시오.
Timo Ohr

4
고마워요! 정말 대단합니다. 검토, 버그보고 및 공유 작업을 오버플로에 넣고 싶었지만 Nexus S에는 표시되지 않았습니다. 사용자는 메뉴 버튼을 클릭조차하지 않습니다. 오버플로를 사용하면 추가 작업을 수행 할 수 있습니다.
Yuriy Kulikov

4
@Ewoks 나는 여기에 의견에 꽤 늦었지만 ActionBarCompat의 최신 버전으로 이것을 시도했지만 작동했습니다.
jacobhyphenated

3
이것은 삼성 갤럭시 S3 및 S4에서 작동하지만 LG G2에서는 작동하지 않습니다 (오버플로 메뉴 버튼을 표시하기 위해 수표를 하드 코딩하는 것으로 의심 됨)
dvd

18
아름다운! 이클립스가 당신에게 Field이것을 선택할 수있는 6 가지 수입품을 원한다면 java.lang.reflect.Field;)
Eugene van der Merwe

35

다음과 같은 메뉴를 정의하여 해결 방법을 사용합니다 (예제에서 ActionBarSherlock 아이콘 사용).

<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/menu_overflow"
        android:icon="@drawable/abs__ic_menu_moreoverflow_normal_holo_light"
        android:orderInCategory="11111"
        android:showAsAction="always">
        <menu>
            <item
                android:id="@+id/menu_overflow_item1"
                android:showAsAction="never"
                android:title="@string/overflow_item1_title"/>
            <item
                android:id="@+id/menu_overflow_item2"
                android:showAsAction="never"
                android:title="@string/overflow_item2_title"/>
        </menu>
    </item>

</menu>

XML에 수동 "오버플로 관리"가 필요할 수도 있지만이 솔루션이 유용하다는 것을 알았습니다.

활동에서 장치가 HW 버튼을 사용하여 오버플로 메뉴를 열도록 할 수도 있습니다.

private Menu mainMenu;

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // TODO: init menu here...
    // then:
    mainMenu=menu;
    return true;
}

@Override
public boolean onKeyUp(int keycode, KeyEvent e) {
    switch(keycode) {
        case KeyEvent.KEYCODE_MENU:
            if (mainMenu !=null) {
                mainMenu.performIdentifierAction(R.id.menu_overflow, 0);
            }
    }

    return super.onKeyUp(keycode, e);
}

:-)


2
HW 버튼을 사용하여 오버플로 메뉴를 여는 방법은 무엇입니까?
bladefury

1
HW 버튼으로 오버플로 메뉴를 여는 방법에 대한 업데이트 된 답변을 참조하십시오. :)
Berťák

11

지원 라이브러리 ( android.support.v7.app.ActionBar) 에서 작업 표시 줄을 사용하는 경우 다음을 사용하십시오.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:yorapp="http://schemas.android.com/apk/res-auto" >

    <item
        android:id="@+id/menu_overflow"
        android:icon="@drawable/icon"
        yourapp:showAsAction="always"
        android:title="">
        <menu>
            <item
                android:id="@+id/item1"
                android:title="item1"/>
            <item
                android:id="@+id/item2"
                android:title="item2"/>
        </menu>
    </item>

</menu>

지원 라이브러리를 사용할 때 나도이 구현은 전후 3.0 장치 모두에 확인 작업
leafcutter

7

이러한 종류의 방법은 Android Developers Design System에 의해 방지되지만 통과하는 방법을 찾았습니다.

이것을 XML 메뉴 파일에 추가하십시오.

<item android:id="@+id/pick_action_provider"
    android:showAsAction="always"
    android:title="More"
    android:icon="@drawable/ic_action_overflow"
    android:actionProviderClass="com.example.AppPickActionProvider" />

다음으로 'AppPickActionProvider'라는 클래스를 만들고 다음 코드를 복사하십시오.

    package com.example;

import android.content.Context;
import android.util.Log;
import android.view.ActionProvider;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
import android.view.View;

public class AppPickActionProvider extends ActionProvider implements
        OnMenuItemClickListener {

    static final int LIST_LENGTH = 3;

    Context mContext;

    public AppPickActionProvider(Context context) {
        super(context);
        mContext = context;
    }

    @Override
    public View onCreateActionView() {
        Log.d(this.getClass().getSimpleName(), "onCreateActionView");

        return null;
    }

    @Override
    public boolean onPerformDefaultAction() {
        Log.d(this.getClass().getSimpleName(), "onPerformDefaultAction");

        return super.onPerformDefaultAction();
    }

    @Override
    public boolean hasSubMenu() {
        Log.d(this.getClass().getSimpleName(), "hasSubMenu");

        return true;
    }

    @Override
    public void onPrepareSubMenu(SubMenu subMenu) {
        Log.d(this.getClass().getSimpleName(), "onPrepareSubMenu");

        subMenu.clear();

        subMenu.add(0, 1, 1, "Item1")
        .setIcon(R.drawable.ic_action_home).setOnMenuItemClickListener(this);

        subMenu.add(0, 2, 1, "Item2")
            .setIcon(R.drawable.ic_action_downloads).setOnMenuItemClickListener(this);
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        switch(item.getItemId())
        {
            case 1:

                // What will happen when the user presses the first menu item ( 'Item1' )

                break;
            case 2:

                // What will happen when the user presses the second menu item ( 'Item2' )

                break;

        }

        return true;
    }
}

이 방법을 사용하는 것과 하위 메뉴를 사용하는 것의 차이점은 다음과 같습니다. stackoverflow.com/a/14634780/878126 ?
안드로이드 개발자

5

알렉산더 루카스는 (불행히도) 정답을 제공했기 때문에 "올바른"답변으로 표시하고 있다고 생각합니다. 내가 여기에 추가하는 다른 대답은 새로운 독자에게 Android 개발자 블로그 의이 게시물 을 가리키는 것입니다. 레벨 11에서 전환 할 때 코드를 처리하는 방법에 대한 특정 제안과 함께 주제에 대한 완전한 토론입니다. 새로운 액션 바에.

메뉴 버튼이 활성화 된 장치에서 메뉴 버튼이 여분의 "액션 오버플로"버튼으로 작동하지 않는 것이 디자인 실수라고 생각합니다.이 시점에서 사용자 경험을 전환하는 더 좋은 방법으로 브리지 아래의 물을 전환하십시오.


나는 디자인 실수에 대해 당신에게 완전히 동의합니다-그리고이 좌절을 찾고 있습니다!
Paul Hunnisett

1
Google 자체가 최근 G + 앱에서 해당 규칙을 위반하기 시작한 것이 아니라면 이에 동의합니다. 그리고 정당하게도. 메뉴 버튼은 레거시가 아니며 SGS3와 같은 새로운 장치에도 있습니다. 불행히도 여기에 있습니다. 그리고 사용성을 심각하게 저해합니다.
Timo Ohr

4

이것이 당신이 찾고있는 것인지 확실하지 않지만 ActionBar의 메뉴 내에 하위 메뉴를 만들고 그 아이콘을 오버플로 메뉴의 아이콘과 일치하도록 설정했습니다. 항목이 자동으로 전송되지는 않지만 (즉, 항상 표시되는 항목과 항상 오버플로되는 항목을 선택해야 함)이 방법이 도움이 될 것 같습니다.


2

ICS가 사전 설치된 상태로 제공되는 Gmail 앱에서 여러 항목을 선택하면 메뉴 버튼이 비활성화됩니다. 여기서 오버플로 메뉴는 실제 메뉴 버튼 대신 오버플로 버튼을 사용하여 트리거되도록 "강제"됩니다. 오버플로 메뉴를 "강제"할 수있는 ActionBarSherlock이라는 타사 라이브러리가 있습니다. 그러나 이것은 API 레벨 14 이하 (pre-ICS)에서만 작동합니다.


2

툴바 를 사용 하면 모든 버전과 모든 장치에서 오버플로를 표시 할 수 있습니다 .2.x 장치에서 시도한 결과 작동합니다.


1

이 문제가 해결되어 죄송합니다.

다음은 오류를 해결하기 위해 수행 한 작업입니다. 레이아웃에 가서 툴바를 포함하는 두 개의 레이아웃을 만들었습니다. 하나는 sdk 버전 8의 레이아웃이고 다른 하나는 sdk 버전 21의 레이아웃이었습니다. 버전 8에서는 android.support.v7.widget.Toolbar를 사용하고 sdk 21 레이아웃에서 android.widget.Toolbar를 사용했습니다.

그런 다음 활동에 툴바를 부풀립니다. SDK가 21 이상인지 확인합니다. 그런 다음 해당 레이아웃을 부풀립니다. 그러면 하드웨어 버튼이 실제로 디자인 한 툴바에 강제로 매핑됩니다.


0

새로운 사용자를 사용하는 사람 Toolbar:

private Toolbar mToolbar;

@Override
protected void onCreate(Bundle bundle) {
    super.onCreate(bundle);

    mToolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(mToolbar);

    ...
}


@Override
public boolean onKeyUp(int keycode, KeyEvent e) {
    switch(keycode) {
        case KeyEvent.KEYCODE_MENU:
            mToolbar.showOverflowMenu();
            return true;
        }

    return super.onKeyUp(keycode, e);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.