是否可以在设计支持库NavigationView中使标题粘滞?
<android.support.design.widget.NavigationView
android:id="@+id/nav_drawer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/nav_header"
app:menu="@menu/nav_drawer"
style="@style/navigation_view_drawer"
/>
编辑:
到目前为止,我的尝试导致了这个
覆盖NavigationView小部件并添加新方法:
public class CustomNavigationView extends NavigationView {
public CustomNavigationView(Context context) {
super(context);
}
public CustomNavigationView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomNavigationView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
// Inflates header as a child of NavigationView, on top of the normal menu
public void createHeader(int res) {
LayoutInflater inflater = LayoutInflater.from(getContext());;
View view = inflater.inflate(res, this, false);
addView(view);
}
}
然后将此添加到活动的onCreate:
CustomNavigationView navigationView = (CustomNavigationView) findViewById(R.id.your_navigation_view);
navigationView.createHeader(R.layout.your_header);
这可以达到预期的效果(如果有点不好意思)但是当菜单项位于标题下方时你仍然可以点击它们,有什么想法可以解决这个问题吗?
答案 0 :(得分:2)
经过大量的实验后,我得到了一些有用的东西......非常hacky,我很想听到你需要改进的建议!
覆盖的NavigationView
public class CustomNavigationView extends NavigationView {
public CustomNavigationView(Context context) {
super(context);
}
public CustomNavigationView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomNavigationView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
// Consumes touch in the NavigationView so it doesn't propagate to views below
public boolean onTouchEvent (MotionEvent me) {
return true;
}
// Inflates header as a child of NavigationView
public void createHeader(int res) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(res, this, false);
// Consumes touch in the header so it doesn't propagate to menu items below
view.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event){
return true;
}
});
addView(view);
}
// Positions and sizes the menu view
public void sizeMenu(View view) {
// Height of header
int header_height = (int) getResources().getDimension(R.dimen.nav_header_height);
// Gets required display metrics
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
float screen_height = displayMetrics.heightPixels;
// Height of menu
int menu_height = (int) (screen_height - header_height);
// Layout params for menu
LayoutParams params = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.BOTTOM;
params.height = menu_height;
view.setLayoutParams(params);
}
}
这是在主要活动的onCreate
// Inflates the nav drawer
CustomNavigationView navigationView = (CustomNavigationView) findViewById(R.id.your_nav_view);
navigationView.createHeader(R.layout.your_nav_header);
// sizes nav drawer menu so it appears under header
ViewGroup parent = (ViewGroup) navigationView;
View view = parent.getChildAt(0);
navigationView.sizeMenu(view);
答案 1 :(得分:1)
我知道这个问题很老,但也许我可以帮助其他人。
<android.support.design.widget.NavigationView
android:id="@+id/nav_drawer"
style="@style/navigation_view_drawer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/nav_header"
app:menu="@menu/nav_drawer">
<include layout="@layout/nav_header" />
</android.support.design.widget.NavigationView>
app:headerLayout 是多余的,但是必需的。
答案 2 :(得分:0)
根据enyciaa的答案编辑 这是简化,更稳定,并支持Android数据绑定 此外,添加了一个API来获取粘性标题视图(在数据绑定到标题布局的情况下)
覆盖的NavigationView
// Add this annotation if databinding is enabled
@BindingMethods({
@BindingMethod(type = StickyHeaderNavigationView.class, attribute = "app:stickyHeader", method = "setStickyHeader")
})
public class StickyHeaderNavigationView extends NavigationView {
@Nullable
View mStickyHeaderView;
public StickyHeaderNavigationView(Context context) {
super(context);
}
public StickyHeaderNavigationView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public StickyHeaderNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// Consumes touch in the NavigationView so it doesn't propagate to views below
@Override
public boolean onTouchEvent(MotionEvent me) {
return true;
}
@Nullable
public View getStickyHeaderView() {
return mStickyHeaderView;
}
// Set a header layout as a child of NavigationView
public void setStickyHeader(@LayoutRes int res) {
if (mStickyHeaderView != null) {
removeView(mStickyHeaderView);
}
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = mStickyHeaderView = inflater.inflate(res, this, false);
// Consumes touch in the header so it doesn't propagate to menu items below
view.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
addView(view);
// Listen to layout update. When ready, we can do #sizeMenu
getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener(this, view));
}
// Positions and sizes the menu view
private void sizeMenu(@NonNull View view, View headerView) {
// Height of header
int headerHeight = headerView.getHeight();
// Gets required display metrics
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
float screenHeight = displayMetrics.heightPixels;
// Height of menu
int menuHeight = (int) (screenHeight - headerHeight);
// Layout params for menu
LayoutParams params = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.BOTTOM;
params.height = menuHeight;
view.setLayoutParams(params);
}
// To listen for layout update, that means header height was calculated
private static class OnGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener {
final WeakReference<StickyHeaderNavigationView> mViewRef;
final WeakReference<View> mHeaderView;
OnGlobalLayoutListener(@NonNull StickyHeaderNavigationView view,
@NonNull View headerView) {
mViewRef = new WeakReference<>(view);
mHeaderView = new WeakReference<>(headerView);
}
@Override
public void onGlobalLayout() {
StickyHeaderNavigationView view = mViewRef.get();
if (view == null) {
return;
}
// Update once only as the header should be fixed size
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
View headerView = mHeaderView.get();
if (headerView == null) {
return;
}
// childAt(0) is the navigation menu
view.sizeMenu(view.getChildAt(0), headerView);
}
}
}
启用数据绑定
将其应用于布局xml
<StickyHeaderNavigationView
...
android:stickyHeader="@{@layout/your_nav_header}" />
未启用数据绑定
将其应用于主要活动的onCreate中
// Inflates the nav drawer
CustomNavigationView navigationView = (CustomNavigationView) findViewById(R.id.your_nav_view);
navigationView.setStickyHeader(R.layout.your_nav_header);