package com.mikepenz.materialdrawer; import android.content.Context; import android.os.Build; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.RelativeLayout; import com.mikepenz.materialdrawer.model.AbstractDrawerItem; import com.mikepenz.materialdrawer.model.ContainerDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.Selectable; import com.mikepenz.materialdrawer.util.DrawerUIUtils; import com.mikepenz.materialize.util.UIUtils; import java.util.List; import androidx.drawerlayout.widget.DrawerLayout; /** * Created by mikepenz on 23.05.15. */ class DrawerUtils { /** * helper method to handle the onClick of the footer * * @param drawer * @param drawerItem * @param v * @param fireOnClick true if we should call the listener, false if not, null to not call the listener and not close the drawer */ public static void onFooterDrawerItemClick(DrawerBuilder drawer, IDrawerItem drawerItem, View v, Boolean fireOnClick) { boolean checkable = !(drawerItem != null && drawerItem instanceof Selectable && !drawerItem.isSelectable()); if (checkable) { drawer.resetStickyFooterSelection(); v.setActivated(true); v.setSelected(true); //remove the selection in the list drawer.getAdapter().deselect(); //find the position of the clicked footer item if (drawer.mStickyFooterView != null && drawer.mStickyFooterView instanceof LinearLayout) { LinearLayout footer = (LinearLayout) drawer.mStickyFooterView; for (int i = 0; i < footer.getChildCount(); i++) { if (footer.getChildAt(i) == v) { drawer.mCurrentStickyFooterSelection = i; break; } } } } if (fireOnClick != null) { boolean consumed = false; if (fireOnClick) { if (drawerItem instanceof AbstractDrawerItem && ((AbstractDrawerItem) drawerItem).getOnDrawerItemClickListener() != null) { consumed = ((AbstractDrawerItem) drawerItem).getOnDrawerItemClickListener().onItemClick(v, -1, drawerItem); } if (drawer.mOnDrawerItemClickListener != null) { consumed = drawer.mOnDrawerItemClickListener.onItemClick(v, -1, drawerItem); } } if (!consumed) { //close the drawer after click drawer.closeDrawerDelayed(); } } } /** * helper method to set the selection of the footer * * @param drawer * @param position * @param fireOnClick */ public static void setStickyFooterSelection(DrawerBuilder drawer, int position, Boolean fireOnClick) { if (position > -1) { if (drawer.mStickyFooterView != null && drawer.mStickyFooterView instanceof LinearLayout) { LinearLayout footer = (LinearLayout) drawer.mStickyFooterView; if (drawer.mStickyFooterDivider) { position = position + 1; } if (footer.getChildCount() > position && position >= 0) { IDrawerItem drawerItem = (IDrawerItem) footer.getChildAt(position).getTag(R.id.material_drawer_item); onFooterDrawerItemClick(drawer, drawerItem, footer.getChildAt(position), fireOnClick); } } } } /** * calculates the position of an drawerItem. searching by it's identifier * * @param identifier * @return */ public static int getPositionByIdentifier(DrawerBuilder drawer, long identifier) { if (identifier != -1) { for (int i = 0; i < drawer.getAdapter().getItemCount(); i++) { if (drawer.getAdapter().getItem(i).getIdentifier() == identifier) { return i; } } } return -1; } /** * gets the drawerItem with the specific identifier from a drawerItem list * * @param drawerItems * @param identifier * @return */ public static IDrawerItem getDrawerItem(List drawerItems, long identifier) { if (identifier != -1) { for (IDrawerItem drawerItem : drawerItems) { if (drawerItem.getIdentifier() == identifier) { return drawerItem; } } } return null; } /** * gets the drawerItem by a defined tag from a drawerItem list * * @param drawerItems * @param tag * @return */ public static IDrawerItem getDrawerItem(List drawerItems, Object tag) { if (tag != null) { for (IDrawerItem drawerItem : drawerItems) { if (tag.equals(drawerItem.getTag())) { return drawerItem; } } } return null; } /** * calculates the position of an drawerItem inside the footer. searching by it's identifier * * @param identifier * @return */ public static int getStickyFooterPositionByIdentifier(DrawerBuilder drawer, long identifier) { if (identifier != -1) { if (drawer.mStickyFooterView != null && drawer.mStickyFooterView instanceof LinearLayout) { LinearLayout footer = (LinearLayout) drawer.mStickyFooterView; int shadowOffset = 0; for (int i = 0; i < footer.getChildCount(); i++) { Object o = footer.getChildAt(i).getTag(R.id.material_drawer_item); //count up the shadowOffset to return the correct position of the given item if (o == null && drawer.mStickyFooterDivider) { shadowOffset = shadowOffset + 1; } if (o != null && o instanceof IDrawerItem && ((IDrawerItem) o).getIdentifier() == identifier) { return i - shadowOffset; } } } } return -1; } /** * helper method to handle the headerView * * @param drawer */ public static void handleHeaderView(DrawerBuilder drawer) { //use the AccountHeader if set if (drawer.mAccountHeader != null) { if (drawer.mAccountHeaderSticky) { drawer.mStickyHeaderView = drawer.mAccountHeader.getView(); } else { drawer.mHeaderView = drawer.mAccountHeader.getView(); drawer.mHeaderDivider = drawer.mAccountHeader.mAccountHeaderBuilder.mDividerBelowHeader; drawer.mHeaderPadding = drawer.mAccountHeader.mAccountHeaderBuilder.mPaddingBelowHeader; } } //sticky header view if (drawer.mStickyHeaderView != null) { //add the sticky footer view and align it to the bottom RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, 1); drawer.mStickyHeaderView.setId(R.id.material_drawer_sticky_header); drawer.mSliderLayout.addView(drawer.mStickyHeaderView, 0, layoutParams); //now align the recyclerView below the stickyFooterView ;) RelativeLayout.LayoutParams layoutParamsListView = (RelativeLayout.LayoutParams) drawer.mRecyclerView.getLayoutParams(); layoutParamsListView.addRule(RelativeLayout.BELOW, R.id.material_drawer_sticky_header); drawer.mRecyclerView.setLayoutParams(layoutParamsListView); //set a background color or the elevation will not work drawer.mStickyHeaderView.setBackgroundColor(UIUtils.getThemeColorFromAttrOrRes(drawer.mActivity, R.attr.material_drawer_background, R.color.material_drawer_background)); if (drawer.mStickyHeaderShadow) { //add a shadow if (Build.VERSION.SDK_INT >= 21) { drawer.mStickyHeaderView.setElevation(UIUtils.convertDpToPixel(4, drawer.mActivity)); } else { View view = new View(drawer.mActivity); view.setBackgroundResource(R.drawable.material_drawer_shadow_bottom); drawer.mSliderLayout.addView(view, RelativeLayout.LayoutParams.MATCH_PARENT, (int) UIUtils.convertDpToPixel(4, drawer.mActivity)); //now align the shadow below the stickyHeader ;) RelativeLayout.LayoutParams lps = (RelativeLayout.LayoutParams) view.getLayoutParams(); lps.addRule(RelativeLayout.BELOW, R.id.material_drawer_sticky_header); view.setLayoutParams(lps); } } //remove the padding of the recyclerView again we have the header on top of it drawer.mRecyclerView.setPadding(0, 0, 0, 0); } // set the header (do this before the setAdapter because some devices will crash else if (drawer.mHeaderView != null) { if (drawer.mRecyclerView == null) { throw new RuntimeException("can't use a headerView without a recyclerView"); } if (drawer.mHeaderPadding) { drawer.getHeaderAdapter().add(new ContainerDrawerItem().withView(drawer.mHeaderView).withHeight(drawer.mHeiderHeight).withDivider(drawer.mHeaderDivider).withViewPosition(ContainerDrawerItem.Position.TOP)); } else { drawer.getHeaderAdapter().add(new ContainerDrawerItem().withView(drawer.mHeaderView).withHeight(drawer.mHeiderHeight).withDivider(drawer.mHeaderDivider).withViewPosition(ContainerDrawerItem.Position.NONE)); } //set the padding on the top to 0 drawer.mRecyclerView.setPadding(drawer.mRecyclerView.getPaddingLeft(), 0, drawer.mRecyclerView.getPaddingRight(), drawer.mRecyclerView.getPaddingBottom()); } } /** * small helper to rebuild the FooterView * * @param drawer */ public static void rebuildStickyFooterView(final DrawerBuilder drawer) { if (drawer.mSliderLayout != null) { if (drawer.mStickyFooterView != null) { drawer.mStickyFooterView.removeAllViews(); //create the divider if (drawer.mStickyFooterDivider) { addStickyFooterDivider(drawer.mStickyFooterView.getContext(), drawer.mStickyFooterView); } //fill the footer with items DrawerUtils.fillStickyDrawerItemFooter(drawer, drawer.mStickyFooterView, new View.OnClickListener() { @Override public void onClick(View v) { IDrawerItem drawerItem = (IDrawerItem) v.getTag(R.id.material_drawer_item); com.mikepenz.materialdrawer.DrawerUtils.onFooterDrawerItemClick(drawer, drawerItem, v, true); } }); drawer.mStickyFooterView.setVisibility(View.VISIBLE); } else { //there was no footer yet. now just create one DrawerUtils.handleFooterView(drawer, new View.OnClickListener() { @Override public void onClick(View v) { IDrawerItem drawerItem = (IDrawerItem) v.getTag(R.id.material_drawer_item); DrawerUtils.onFooterDrawerItemClick(drawer, drawerItem, v, true); } }); } setStickyFooterSelection(drawer, drawer.mCurrentStickyFooterSelection, false); } } /** * helper method to handle the footerView * * @param drawer */ public static void handleFooterView(DrawerBuilder drawer, View.OnClickListener onClickListener) { Context ctx = drawer.mSliderLayout.getContext(); //use the StickyDrawerItems if set if (drawer.mStickyDrawerItems != null && drawer.mStickyDrawerItems.size() > 0) { drawer.mStickyFooterView = DrawerUtils.buildStickyDrawerItemFooter(ctx, drawer, onClickListener); } //sticky footer view if (drawer.mStickyFooterView != null) { //add the sticky footer view and align it to the bottom RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 1); drawer.mStickyFooterView.setId(R.id.material_drawer_sticky_footer); drawer.mSliderLayout.addView(drawer.mStickyFooterView, layoutParams); if ((drawer.mTranslucentNavigationBar || drawer.mFullscreen) && Build.VERSION.SDK_INT >= 19) { drawer.mStickyFooterView.setPadding(0, 0, 0, UIUtils.getNavigationBarHeight(ctx)); } //now align the recyclerView above the stickyFooterView ;) RelativeLayout.LayoutParams layoutParamsListView = (RelativeLayout.LayoutParams) drawer.mRecyclerView.getLayoutParams(); layoutParamsListView.addRule(RelativeLayout.ABOVE, R.id.material_drawer_sticky_footer); drawer.mRecyclerView.setLayoutParams(layoutParamsListView); //handle shadow on top of the sticky footer if (drawer.mStickyFooterShadow) { drawer.mStickyFooterShadowView = new View(ctx); drawer.mStickyFooterShadowView.setBackgroundResource(R.drawable.material_drawer_shadow_top); drawer.mSliderLayout.addView(drawer.mStickyFooterShadowView, RelativeLayout.LayoutParams.MATCH_PARENT, ctx.getResources().getDimensionPixelSize(R.dimen.material_drawer_sticky_footer_elevation)); //now align the shadow below the stickyHeader ;) RelativeLayout.LayoutParams lps = (RelativeLayout.LayoutParams) drawer.mStickyFooterShadowView.getLayoutParams(); lps.addRule(RelativeLayout.ABOVE, R.id.material_drawer_sticky_footer); drawer.mStickyFooterShadowView.setLayoutParams(lps); } //remove the padding of the recyclerView again we have the footer below it drawer.mRecyclerView.setPadding(drawer.mRecyclerView.getPaddingLeft(), drawer.mRecyclerView.getPaddingTop(), drawer.mRecyclerView.getPaddingRight(), ctx.getResources().getDimensionPixelSize(R.dimen.material_drawer_padding)); } // set the footer (do this before the setAdapter because some devices will crash else if (drawer.mFooterView != null) { if (drawer.mRecyclerView == null) { throw new RuntimeException("can't use a footerView without a recyclerView"); } if (drawer.mFooterDivider) { drawer.getFooterAdapter().add(new ContainerDrawerItem().withView(drawer.mFooterView).withViewPosition(ContainerDrawerItem.Position.BOTTOM)); } else { drawer.getFooterAdapter().add(new ContainerDrawerItem().withView(drawer.mFooterView).withViewPosition(ContainerDrawerItem.Position.NONE)); } } } /** * build the sticky footer item view * * @return */ public static ViewGroup buildStickyDrawerItemFooter(Context ctx, DrawerBuilder drawer, View.OnClickListener onClickListener) { //create the container view final LinearLayout linearLayout = new LinearLayout(ctx); linearLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); linearLayout.setOrientation(LinearLayout.VERTICAL); //set the background color to the drawer background color (if it has alpha the shadow won't be visible) linearLayout.setBackgroundColor(UIUtils.getThemeColorFromAttrOrRes(ctx, R.attr.material_drawer_background, R.color.material_drawer_background)); //create the divider if (drawer.mStickyFooterDivider) { addStickyFooterDivider(ctx, linearLayout); } fillStickyDrawerItemFooter(drawer, linearLayout, onClickListener); return linearLayout; } /** * adds the shadow to the stickyFooter * * @param ctx * @param footerView */ private static void addStickyFooterDivider(Context ctx, ViewGroup footerView) { LinearLayout divider = new LinearLayout(ctx); LinearLayout.LayoutParams dividerParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); divider.setMinimumHeight((int) UIUtils.convertDpToPixel(1, ctx)); divider.setOrientation(LinearLayout.VERTICAL); divider.setBackgroundColor(UIUtils.getThemeColorFromAttrOrRes(ctx, R.attr.material_drawer_divider, R.color.material_drawer_divider)); footerView.addView(divider, dividerParams); } /** * helper method to fill the sticky footer with it's elements * * @param drawer * @param container * @param onClickListener */ public static void fillStickyDrawerItemFooter(DrawerBuilder drawer, ViewGroup container, View.OnClickListener onClickListener) { //add all drawer items for (IDrawerItem drawerItem : drawer.mStickyDrawerItems) { View view = drawerItem.generateView(container.getContext(), container); view.setTag(drawerItem); if (drawerItem.isEnabled()) { //UIUtils.setBackground(view, UIUtils.getSelectableBackground(container.getContext(), selected_color, drawerItem.isSelectedBackgroundAnimated())); view.setOnClickListener(onClickListener); } container.addView(view); //for android API 17 --> Padding not applied via xml DrawerUIUtils.setDrawerVerticalPadding(view); } //and really. don't ask about this. it won't set the padding if i don't set the padding for the container container.setPadding(0, 0, 0, 0); } /** * helper to extend the layoutParams of the drawer * * @param params * @return */ public static DrawerLayout.LayoutParams processDrawerLayoutParams(DrawerBuilder drawer, DrawerLayout.LayoutParams params) { if (params != null) { if (drawer.mDrawerGravity != null && (drawer.mDrawerGravity == Gravity.RIGHT || drawer.mDrawerGravity == Gravity.END)) { params.rightMargin = 0; if (Build.VERSION.SDK_INT >= 17) { params.setMarginEnd(0); } params.leftMargin = drawer.mActivity.getResources().getDimensionPixelSize(R.dimen.material_drawer_margin); if (Build.VERSION.SDK_INT >= 17) { params.setMarginEnd(drawer.mActivity.getResources().getDimensionPixelSize(R.dimen.material_drawer_margin)); } } if (drawer.mDrawerWidth > -1) { params.width = drawer.mDrawerWidth; } else { params.width = DrawerUIUtils.getOptimalDrawerWidth(drawer.mActivity); } } return params; } }