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 레이아웃을 래핑하는 것입니다.
-
루트 레이아웃은
<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를 사용하는 경우 마법사가 기본 마법사를 만들고 옵션이 무엇인지 확인할 수 있습니다.
-
앱 바 레이아웃은 일반적으로 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" />
-
콘텐츠 레이아웃은 원하는 레이아웃이 될 수 있습니다. 이것은 활동의 주요 내용을 포함하는 레이아웃입니다 (탐색 서랍이나 앱 바는 포함되지 않음).
이제이 모든 것의 멋진 점은이 두 레이아웃으로 각 활동을 래핑 할 수 있지만 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).
-
SplashActivity : 조각을 사용하지 않고 FullScreen 테마를 사용합니다.
-
LoginSignUpActivity : NavigationDrawer를 전혀 필요로하지 않고 뒤로 단추도 필요하지 않으므로 일반 도구 모음을 사용하기 만하면 최소한 3 개 또는 4 개의 조각이 필요합니다. 액션 바없는 테마 사용
-
HomeActivity 또는 DashBoard Activity : 액션 바 없음 테마를 사용합니다. 여기에는 탐색 드로어가 필요하며, 그 다음에 나오는 모든 화면은 공유 드로어와 함께 리프보기까지 프래그먼트 또는 중첩 된 프래그먼트입니다. 이 액티비티에서는 모든 설정, 사용자 프로필 등이 조각으로 표시됩니다. 여기의 조각은 백 스택에 추가되지 않으며 서랍 메뉴 항목에서 열립니다. 서랍 대신 뒤로 버튼이 필요한 조각의 경우 아래에 네 번째 종류의 활동이 있습니다.
-
서랍이없는 활동. 이 액티비티에는 상단에 뒤로 버튼이 있으며 내부 조각은 동일한 작업 표시 줄을 공유합니다. 탐색 내역이 있으므로 이러한 조각은 백 스택에 추가됩니다.
[추가 지침은 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 ()를 사용하지 마십시오. 그러나 여전히 이미지를 클릭하면 서랍이 보이지 않습니다. 드래그하면 목록 항목이 없어도 서랍이 보입니다. 나는 많이 시도했지만 성공하지 못했습니다. 이를 위해 운동이 필요합니다 …