다른 활동에서 동일한 탐색 창

developer.android.com 웹 사이트 의 자습서에 표시된 것처럼 작동하는 탐색 드로어를 작성했습니다 . 그러나 이제 내 응용 프로그램의 여러 활동을 위해 NavigationDrawer.class에서 만든 하나의 Navigation Drawer를 사용하고 싶습니다.

내 질문은, 여기 누군가가 작은 튜토리얼을 만들 수 있다면, 여러 활동에 하나의 탐색 서랍을 사용하는 방법을 설명합니다.

여러 활동에 대한 이 Answer Android Navigation Drawer에서 처음 읽었습니다.

하지만 내 프로젝트에서 작동하지 않았습니다.

public class NavigationDrawer extends Activity {
public DrawerLayout drawerLayout;
public ListView drawerList;
private ActionBarDrawerToggle drawerToggle;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawerToggle = new ActionBarDrawerToggle((Activity) this, drawerLayout, R.drawable.ic_drawer, 0, 0) {

        public void onDrawerClosed(View view) {
            getActionBar().setTitle(R.string.app_name);
        }

        public void onDrawerOpened(View drawerView) {
            getActionBar().setTitle(R.string.menu);
        }
    };
    drawerLayout.setDrawerListener(drawerToggle);

    getActionBar().setDisplayHomeAsUpEnabled(true);
    getActionBar().setHomeButtonEnabled(true);

    layers = getResources().getStringArray(R.array.layers_array);
    drawerList = (ListView) findViewById(R.id.left_drawer);
    View header = getLayoutInflater().inflate(R.layout.drawer_list_header, null);
    drawerList.addHeaderView(header, null, false);
    drawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, android.R.id.text1,
            layers));
    View footerView = ((LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
            R.layout.drawer_list_footer, null, false);
    drawerList.addFooterView(footerView);

    drawerList.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3) {
            map.drawerClickEvent(pos);
        }
    });
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    if (drawerToggle.onOptionsItemSelected(item)) {
        return true;
    }
    return super.onOptionsItemSelected(item);

}

@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    drawerToggle.syncState();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    drawerToggle.onConfigurationChanged(newConfig);
}
}

이 활동에서 나는 탐색 서랍을 갖고 싶어서 ‘NavigationDrawer’를 확장하고 다른 활동에서는 동일한 탐색 서랍을 사용하려고합니다.

  public class SampleActivity extends NavigationDrawer {...}

무엇을 바꿔야할지 모르겠습니다 …



답변

탐색 드로어를 원하면 조각을 사용해야합니다. 지난주에이 튜토리얼을 따랐으며 훌륭하게 작동합니다.

http://developer.android.com/training/implementing-navigation/nav-drawer.html

이 튜토리얼에서 샘플 코드를 다운로드하여이를 수행하는 방법을 확인할 수도 있습니다.


파편없이 :

이것은 BaseActivity 코드입니다.

public class BaseActivity extends Activity
{
    public DrawerLayout drawerLayout;
    public ListView drawerList;
    public String[] layers;
    private ActionBarDrawerToggle drawerToggle;
    private Map map;

    protected void onCreate(Bundle savedInstanceState)
    {
        // R.id.drawer_layout should be in every activity with exactly the same id.
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

        drawerToggle = new ActionBarDrawerToggle((Activity) this, drawerLayout, R.drawable.ic_drawer, 0, 0)
        {
            public void onDrawerClosed(View view)
            {
                getActionBar().setTitle(R.string.app_name);
            }

            public void onDrawerOpened(View drawerView)
            {
                getActionBar().setTitle(R.string.menu);
            }
        };
        drawerLayout.setDrawerListener(drawerToggle);

        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);

        layers = getResources().getStringArray(R.array.layers_array);
        drawerList = (ListView) findViewById(R.id.left_drawer);
        View header = getLayoutInflater().inflate(R.layout.drawer_list_header, null);
        drawerList.addHeaderView(header, null, false);
        drawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, android.R.id.text1,
                layers));
        View footerView = ((LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
                R.layout.drawer_list_footer, null, false);
        drawerList.addFooterView(footerView);

        drawerList.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3) {
                map.drawerClickEvent(pos);
            }
        });
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        if (drawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        return super.onOptionsItemSelected(item);

    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        drawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        drawerToggle.onConfigurationChanged(newConfig);
    }
}

탐색 드로어가 필요한 다른 모든 활동은 활동 자체 대신이 활동을 확장해야합니다. 예 :

public class AnyActivity extends BaseActivity
{
    //Because this activity extends BaseActivity it automatically has the navigation drawer
    //You can just write your normal Activity code and you don't need to add anything for the navigation drawer
}

XML

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- The main content view -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <!-- Put what you want as your normal screen in here, you can also choose for a linear layout or any other layout, whatever you prefer -->
    </FrameLayout>
    <!-- The navigation drawer -->
    <ListView android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#111"/>
</android.support.v4.widget.DrawerLayout>

편집하다:

나는 약간의 어려움을 겪었으므로 NullPointerExceptions를 얻는다면 여기에 해결책이 있습니다. BaseActivity에서 onCreate 함수를로 변경하십시오 protected void onCreateDrawer(). 나머지는 동일하게 유지 될 수 있습니다. BaseActivity를 확장하는 활동에서 코드를 다음 순서로 넣으십시오.

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity);
    super.onCreateDrawer();

이것은 내 문제를 해결하는 데 도움이되었습니다. 도움이되기를 바랍니다.

질문이 있으시면 여러 활동이 포함 된 탐색 창을 만드는 방법입니다.


편집 2 :

@GregDan이 말했듯이 onCreateDrawer를 BaseActivity재정의 setContentView()하고 호출 할 수 있습니다 .

@Override
public void setContentView(@LayoutRes int layoutResID)
{
    super.setContentView(layoutResID);
    onCreateDrawer() ;
}


답변

최고의 구현을 찾았습니다. 그것은에서의 구글 I / O 2014 응용 프로그램.

그들은 Kevin과 같은 접근법을 사용합니다. I / O 앱의 불필요한 모든 항목에서 자신을 추상화 할 수 있다면 필요한 모든 것을 추출 할 수 있으며 Google은 탐색 드로어 패턴의 올바른 사용법을 보장합니다. 각 활동에는 선택적 DrawerLayout으로 기본 레이아웃이 있습니다. 흥미로운 부분은 다른 화면으로 이동하는 방법입니다. 다음 BaseActivity과 같이 구현됩니다 .

private void goToNavDrawerItem(int item) {
        Intent intent;
        switch (item) {
            case NAVDRAWER_ITEM_MY_SCHEDULE:
                intent = new Intent(this, MyScheduleActivity.class);
                startActivity(intent);
                finish();
                break;

이것은 현재 조각을 조각 트랜잭션으로 대체하는 일반적인 방법과 다릅니다. 그러나 사용자는 시각적 차이를 발견하지 못합니다.


답변

따라서이 답변은 몇 년 늦었지만 누군가는 그것을 감사 할 것입니다. Android는 여러 활동이 포함 된 하나의 탐색 창을보다 쉽게 ​​사용할 수있는 새로운 위젯을 제공했습니다.

android.support.design.widget.NavigationView는 모듈 식이며 메뉴 폴더에 자체 레이아웃이 있습니다. 사용하는 방법은 다음과 같은 방식으로 xml 레이아웃을 래핑하는 것입니다.

  1. 루트 레이아웃은 <include ... />랩핑되는 레이아웃 (2 참조)과 android.support.design.widget.NavigationView의 두 자식을 포함 하는 android.support.v4.widget.DrawerLayout입니다.

    <android.support.v4.widget.DrawerLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:openDrawer="start">
    
    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    
    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer" />

nav_header_main은 Navigation Drawar의 헤더에 방향 = 수직 인 LinearLayout입니다.

activity_main_drawer는 res / menu 디렉토리의 메뉴 xml입니다. 선택한 항목과 그룹을 포함 할 수 있습니다. AndroidStudio Gallery를 사용하는 경우 마법사가 기본 마법사를 만들고 옵션이 무엇인지 확인할 수 있습니다.

  1. 앱 바 레이아웃은 일반적으로 android.support.design.widget.CoordinatorLayout이며 여기에는 android.support.design.widget.AppBarLayout (android.support.v7.widget.Toolbar 포함) 및 <include ... >for. 실제 내용 (3 참조)

    <android.support.design.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="yourpackage.MainActivity">
    
     <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />
    
    </android.support.design.widget.AppBarLayout>
    
    <include layout="@layout/content_main" />

  2. 콘텐츠 레이아웃은 원하는 레이아웃이 될 수 있습니다. 이것은 활동의 주요 내용을 포함하는 레이아웃입니다 (탐색 서랍이나 앱 바는 포함되지 않음).

이제이 모든 것의 멋진 점은이 두 레이아웃으로 각 활동을 래핑 할 수 있지만 NavigationView (1 단계 참조)가 항상 activity_main_drawer (또는 무엇이든)를 가리 키도록한다는 것입니다. 즉, 모든 활동에 대해 동일한 (*) 탐색 창을 갖게됩니다.

  • 그것들은 NavigationView 의 동일한 인스턴스 는 아니지만 공정하게 말하면 위에서 설명한 BaseActivity 솔루션으로는 불가능했습니다.

답변

활동 그룹간에 공통 탐색 드로어를 재사용하는 가장 쉬운 방법

app_base_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <FrameLayout
        android:id="@+id/view_stub"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </FrameLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:menu="@menu/menu_test"
        />
</android.support.v4.widget.DrawerLayout>

AppBaseActivity.java

/*
* This is a simple and easy approach to reuse the same
* navigation drawer on your other activities. Just create
* a base layout that conains a DrawerLayout, the
* navigation drawer and a FrameLayout to hold your
* content view. All you have to do is to extend your
* activities from this class to set that navigation
* drawer. Happy hacking :)
* P.S: You don't need to declare this Activity in the
* AndroidManifest.xml. This is just a base class.
*/
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

public abstract class AppBaseActivity extends AppCompatActivity implements MenuItem.OnMenuItemClickListener {
    private FrameLayout view_stub; //This is the framelayout to keep your content view
    private NavigationView navigation_view; // The new navigation view from Android Design Library. Can inflate menu resources. Easy
    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mDrawerToggle;
    private Menu drawerMenu;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.app_base_layout);// The base layout that contains your navigation drawer.
        view_stub = (FrameLayout) findViewById(R.id.view_stub);
        navigation_view = (NavigationView) findViewById(R.id.navigation_view);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, 0, 0);
        mDrawerLayout.setDrawerListener(mDrawerToggle);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        drawerMenu = navigation_view.getMenu();
        for(int i = 0; i < drawerMenu.size(); i++) {
          drawerMenu.getItem(i).setOnMenuItemClickListener(this);
        }
        // and so on...
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    /* Override all setContentView methods to put the content view to the FrameLayout view_stub
     * so that, we can make other activity implementations looks like normal activity subclasses.
     */
    @Override
    public void setContentView(int layoutResID) {
        if (view_stub != null) {
            LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT);
            View stubView = inflater.inflate(layoutResID, view_stub, false);
            view_stub.addView(stubView, lp);
        }
    }

    @Override
    public void setContentView(View view) {
        if (view_stub != null) {
            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT);
            view_stub.addView(view, lp);
        }
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        if (view_stub != null) {
            view_stub.addView(view, params);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Pass the event to ActionBarDrawerToggle, if it returns
        // true, then it has handled the app icon touch event
        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        // Handle your other action bar items...

        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.item1:
                // handle it
                break;
            case R.id.item2:
                // do whatever
                break;
            // and so on...
        }
        return false;
    }
}


답변

원래 포스터가 요구하는 것을 수행하려는 다른 사람은 Kevin이 말한 방식 대신 조각을 사용하는 것이 좋습니다. 이를 수행하는 방법에 대한 훌륭한 자습서는 다음과 같습니다.

https://github.com/codepath/android_guides/wiki/Fragment-Navigation-Drawer

프래그먼트 대신 액티비티를 사용하도록 선택하면 새 액티비티로 이동할 때마다 탐색 드로어가 다시 작성되는 문제가 발생합니다. 이로 인해 매번 탐색 서랍이보기 흉하고 느리게 렌더링됩니다.


답변

내 제안은 : 활동을 전혀 사용하지 말고 조각을 사용하고 첫 번째 조각을 표시하는 컨테이너 (예 : 선형 레이아웃)에서 교체하십시오.

코드는 Android Developer Tutorials에서 사용할 수 있습니다. 사용자 정의하면됩니다.

http://developer.android.com/training/implementing-navigation/nav-drawer.html

애플리케이션에서 점점 더 많은 프래그먼트를 사용해야하며 외부 애플리케이션과 별도로 AndroidManifest.xml에서 언급 한 네 가지 기본 활동 만 애플리케이션에 국한되어야합니다 (FacebookActivity).

  1. SplashActivity : 조각을 사용하지 않고 FullScreen 테마를 사용합니다.

  2. LoginSignUpActivity : NavigationDrawer를 전혀 필요로하지 않고 뒤로 단추도 필요하지 않으므로 일반 도구 모음을 사용하기 만하면 최소한 3 개 또는 4 개의 조각이 필요합니다. 액션 바없는 테마 사용

  3. HomeActivity 또는 DashBoard Activity : 액션 바 없음 테마를 사용합니다. 여기에는 탐색 드로어가 필요하며, 그 다음에 나오는 모든 화면은 공유 드로어와 함께 리프보기까지 프래그먼트 또는 중첩 된 프래그먼트입니다. 이 액티비티에서는 모든 설정, 사용자 프로필 등이 조각으로 표시됩니다. 여기의 조각은 백 스택에 추가되지 않으며 서랍 메뉴 항목에서 열립니다. 서랍 대신 뒤로 버튼이 필요한 조각의 경우 아래에 네 번째 종류의 활동이 있습니다.

  4. 서랍이없는 활동. 이 액티비티에는 상단에 뒤로 버튼이 있으며 내부 조각은 동일한 작업 표시 줄을 공유합니다. 탐색 내역이 있으므로 이러한 조각은 백 스택에 추가됩니다.

[추가 지침은 https://stackoverflow.com/a/51100507/787399 참조 ]

행복한 코딩!


답변

기본 활동에서이 코드를 업데이트하십시오. 그리고 활동 XML에 drawer_list_header를 포함시키는 것을 잊지 마십시오.

super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
setContentView(R.layout.drawer_list_header);

활동에 request ()를 사용하지 마십시오. 그러나 여전히 이미지를 클릭하면 서랍이 보이지 않습니다. 드래그하면 목록 항목이 없어도 서랍이 보입니다. 나는 많이 시도했지만 성공하지 못했습니다. 이를 위해 운동이 필요합니다 …