androidandroiddesignsupport

How to make NavigationView header sticky


Is it possible to make the header sticky in the design support library 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"
    />

EDIT:

My attempts so far have led to this

Overriding the NavigationView widget and adding a new method:

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);
}

}

Then adding this to the onCreate of the activity:

CustomNavigationView navigationView = (CustomNavigationView) findViewById(R.id.your_navigation_view);
navigationView.createHeader(R.layout.your_header);

This achieves the desired effect (if a bit hackily) but when menu items are below the header you can still click them, any ideas to fix this?


Solution

  • After lots of experimenting I've got something that works...it's very hacky and I'd love to hear any suggestions you have to improve it!

    The overrided 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);
    }
    

    }

    And this in the onCreate of main activity

    // 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);