Android Studio 2.1.3
我有这个设计我想跟随。
在第一个抽屉布局上,我有一个设置选项。
当用户点击时,它将打开第二个抽象布局,如下所示。
用户可以点击箭头Main Menu
返回第一个。
这可能吗?
非常感谢任何建议
答案 0 :(得分:6)
目前还不清楚您希望如何实现抽屉UI,因此以下解决方案非常通用,因为它应该适用于NavigationView
s,RecyclerView
或几乎任何类型的{ {1}}你想要的。
此解决方案使用自定义View
子类作为ViewSwitcher
的左抽屉,并保存两个子DrawerLayout
,其中一个是主抽屉View
,另一个是打开它的第二个抽屉。
View
类是一个相对简单的DoubleDrawerView
,它加载自己的ViewSwitcher
,并适当地调整它们以产生第二个抽屉打开和关闭第一个抽屉的效果。它跟踪自己的状态,以便在设备轮换后可以正确恢复等等。
Animation
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];
}
};
}
}
使用以下XML文件作为其DoubleDrawerView
。这些应该在项目的Animation
文件夹中。
res/anim/
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" />
,其抽屉有DrawerLayout
,其中有两个简单的DoubleDrawerView
。请注意,主抽屉NavigationView
必须首先列在View
内,第二个内抽屉DoubleDrawerView
后面。{/ p>
View
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>
的一些简单的res/menu/
文件。
NavigationView
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>
中,我们只是引用了Activity
和DoubleDrawerView
,并实现NavigationView
来相应地打开和关闭内部抽屉。
OnNavigationItemSelectedListener
答案 1 :(得分:4)
此解决方案使用两个DrawerLayout
,一个嵌套在另一个中,代替自定义View
。这可能稍微容易实现,但它需要在Activity
本身中使用更专业的代码,因此它将更紧密地耦合到它所使用的任何类中。
Activity
的布局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" />
<android.support.v4.widget.DrawerLayout
android:id="@+id/inner_drawer_layout"
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="240dp"
android:layout_height="match_parent"
android:layout_gravity="left"
app:menu="@menu/navigation_settings" />
</android.support.v4.widget.DrawerLayout>
</android.support.v4.widget.DrawerLayout>
上面的示例NavigationView
使用与my other answer here中显示的相同的菜单文件。
在Activity
中,我们获得了对DrawerLayout
的引用,并在启动时在内部设置了稀松布颜色和锁定模式。我们还需要自己处理后退按钮,因为在第一次处理它时会增加第二个DrawerLayout
混乱。打开和关闭内部抽屉时,我们需要适当设置锁定模式,以防止拖动内部抽屉。
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private DrawerLayout drawerLayout, innerDrawerLayout;
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);
innerDrawerLayout = (DrawerLayout) findViewById(R.id.inner_drawer_layout);
mainNavigationView = (NavigationView) findViewById(R.id.main_navigation_view);
settingsNavigationView = (NavigationView) findViewById(R.id.settings_navigation_view);
mainNavigationView.setNavigationItemSelectedListener(this);
settingsNavigationView.setNavigationItemSelectedListener(this);
innerDrawerLayout.setScrimColor(Color.TRANSPARENT);
innerDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
drawerLayout.openDrawer(Gravity.LEFT);
}
@Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(Gravity.LEFT)) {
drawerLayout.closeDrawer(Gravity.LEFT);
}
else {
super.onBackPressed();
}
}
private void openInnerDrawer() {
innerDrawerLayout.openDrawer(Gravity.LEFT);
innerDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
}
private void closeInnerDrawer() {
innerDrawerLayout.closeDrawer(Gravity.LEFT);
innerDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
@Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_open_settings:
openInnerDrawer();
break;
case R.id.menu_close_settings:
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;
}
}