Nie wiadomo, jak dokładnie chcesz realizować swoje szuflady UI, więc następujące rozwiązanie jest dość ogólny, w który powinien działać z NavigationView
s, RecyclerView
s, czyli prawie dowolnego typu z View
s, które chcesz.
Rozwiązanie to wykorzystuje niestandardowy ViewSwitcher
podklasę, która działa jak lewej szuflady DrawerLayout
„s, i posiada dwie potomne View
s, jeden jako główny szuflada View
, a drugi jest druga szuflada, która otwiera się nad nim.
Klasa DoubleDrawerView
jest stosunkowo proste ViewSwitcher
który ładuje własne Animation
s, a ongluje je odpowiednio dać efekt drugiego otworu i zamykania szuflady na pierwszej. Śledzi własnego stanu tak, że może on zostać przywrócone poprawnie po obróceniu urządzenia itp
public class DoubleDrawerView extends ViewSwitcher {
private static final int NONE = -1;
private static final int MAIN_VIEW_INDEX = 0;
private static final int DRAWER_VIEW_INDEX = 1;
private Animation slideInAnimation, slideOutAnimation, noAnimation;
private boolean animating = false;
private Animation.AnimationListener listener = new Animation.AnimationListener() {
@Override
public void onAnimationEnd(Animation anim) {
animating = false;
}
@Override
public void onAnimationStart(Animation anim) {}
@Override
public void onAnimationRepeat(Animation anim) {}
};
public DoubleDrawerView(Context context) {
this(context, null);
}
public DoubleDrawerView(Context context, AttributeSet attrs) {
super(context, attrs);
slideInAnimation = AnimationUtils.loadAnimation(context, R.anim.slide_in_left);
slideOutAnimation = AnimationUtils.loadAnimation(context, R.anim.slide_out_left);
noAnimation = AnimationUtils.loadAnimation(context, R.anim.none);
noAnimation.setAnimationListener(listener);
}
public void openInnerDrawer() {
if (getDisplayedChild() != DRAWER_VIEW_INDEX) {
setChildAndAnimate(DRAWER_VIEW_INDEX, true);
}
}
public void closeInnerDrawer() {
if (getDisplayedChild() != MAIN_VIEW_INDEX) {
setChildAndAnimate(MAIN_VIEW_INDEX, true);
}
}
public boolean isInnerDrawerOpen() {
return getDisplayedChild() == DRAWER_VIEW_INDEX;
}
private void setChildAndAnimate(int whichChild, boolean doAnimate) {
if (doAnimate) {
setAnimationForChild(whichChild);
}
else {
setAnimationForChild(NONE);
}
animating = doAnimate;
setDisplayedChild(whichChild);
}
private void setAnimationForChild(int whichChild) {
if (whichChild == DRAWER_VIEW_INDEX) {
setInAnimation(slideInAnimation);
setOutAnimation(noAnimation);
}
else if (whichChild == MAIN_VIEW_INDEX) {
setInAnimation(noAnimation);
setOutAnimation(slideOutAnimation);
}
else {
setInAnimation(null);
setOutAnimation(null);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (animating) {
return true;
}
else {
return super.onInterceptTouchEvent(ev);
}
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.whichChild = getDisplayedChild();
return ss;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setChildAndAnimate(ss.whichChild, false);
}
private static class SavedState extends BaseSavedState {
int whichChild;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
whichChild = in.readInt();
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(whichChild);
}
public static final Parcelable.Creator<SavedState>
CREATOR = new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
DoubleDrawerView
wykorzystuje następujące pliki XML dla swoich Animation
s. Powinny one znajdować się w folderze res/anim/
Twojego projektu.
slide_in_left.xml
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="-100%p" android:toXDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
slide_out_left.xml
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0" android:toXDelta="-100%p"
android:duration="@android:integer/config_mediumAnimTime"/>
none.xml
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="1.0" android:toAlpha="1.0"
android:duration="@android:integer/config_mediumAnimTime" />
układ tym przykładzie jest to standardowy DrawerLayout
z DoubleDrawerView
do szuflady, a dwa proste NavigationView
s tam. Pamiętaj, że główna szuflada View
musi być wymieniona najpierw wewnątrz DoubleDrawerView
, z drugą, wewnętrzną szufladą View
po.
activity_main.xml
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.example.doubledrawer.DoubleDrawerView
android:id="@+id/double_drawer_view"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="left">
<android.support.design.widget.NavigationView
android:id="@+id/main_navigation_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:menu="@menu/navigation_main" />
<android.support.design.widget.NavigationView
android:id="@+id/settings_navigation_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:menu="@menu/navigation_settings" />
</com.example.doubledrawer.DoubleDrawerView>
</android.support.v4.widget.DrawerLayout>
Dla kompletnego wyciąć i wkleić przykład niektóre proste res/menu/
pliki dla NavigationView
s powyżej.
navigation_main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group
android:id="@+id/group_screens"
android:checkableBehavior="single">
<item
android:id="@+id/menu_screen_1"
android:title="Screen 1" />
<item
android:id="@+id/menu_screen_2"
android:title="Screen 2"/>
</group>
<item
android:id="@+id/menu_open_settings"
android:title="Open Settings" />
</menu>
navigation_settings.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_close_settings"
android:title="Back to Main" />
<group
android:id="@+id/group_settings">
<item
android:id="@+id/menu_setting_1"
android:title="Setting 1" />
<item
android:id="@+id/menu_setting_2"
android:title="Setting 2" />
</group>
</menu>
W przykładzie Activity
, my po prostu odnośniki do DoubleDrawerView
i NavigationView
s, i wdrożyć OnNavigationItemSelectedListener
aby otworzyć i zamknąć szufladę wewnętrzną odpowiednio.
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private DrawerLayout drawerLayout;
private DoubleDrawerView doubleDrawerView;
private NavigationView mainNavigationView, settingsNavigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
doubleDrawerView = (DoubleDrawerView) findViewById(R.id.double_drawer_view);
mainNavigationView = (NavigationView) findViewById(R.id.main_navigation_view);
settingsNavigationView = (NavigationView) findViewById(R.id.settings_navigation_view);
mainNavigationView.setNavigationItemSelectedListener(this);
settingsNavigationView.setNavigationItemSelectedListener(this);
drawerLayout.openDrawer(Gravity.LEFT);
}
@Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_open_settings:
doubleDrawerView.openInnerDrawer();
break;
case R.id.menu_close_settings:
doubleDrawerView.closeInnerDrawer();
break;
// Additional cases as needed
// This example simply Toasts the title for the extra sample items
default:
Toast.makeText(this, item.getTitle(), Toast.LENGTH_SHORT).show();
}
return true;
}
}
Jest to możliwe, ale nie ze standardowym plikiem menu xml. Trzeba zrobić mały hack, dodając niestandardowy układ do 'NavigationView'. –
Czy interesuje Cię tylko jak otworzyć drugą szufladę nad pierwszą? Chodzi mi o to, czy pytasz również, jak stylizować te poszczególne przedmioty, czy po prostu potrzebujesz funkcji podwójnej szuflady? –
Chciałbym kliknąć ustawienia w pierwszym menu, a podmenu ustawień będzie animowane nad pierwszym. Zostało to zrobione z aplikacji Amazon, którą próbowałem skopiować w mojej własnej. – ant2009