Add elevation/shadow on toolbar for pre-lollipop devices

前端 未结 8 1130
猫巷女王i
猫巷女王i 2020-11-28 05:39

I updated my android app to the new material design, but I also wanted to add some shadow or elevation to the Toolbar. There seem to be some (hacky) ways of doing it via ima

相关标签:
8条回答
  • 2020-11-28 06:06

    Try using the AppBarLayout inside the activity layout. Try:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
            <include
                layout="@layout/Toolbar" />
        </android.support.design.widget.AppBarLayout>
    
        <fragment
            class="OverAllField.XamarinAndroid.Fragments.Planning.PlanningFragment"
            android:id="@+id/PlanningFragment"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />
    </LinearLayout>
    

    Toolbar.xml

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.widget.Toolbar
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/Toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
    
    0 讨论(0)
  • 2020-11-28 06:17

    I have also lost 1 day on this issue, but I finally figured out a way to make it work.

    /**
     * Controller for the toolbar which will take care of the drop down shadow also on pre-lollipop devices.
     * <br/>
     * The controller also handles the status bar based on the state of the toolbar.
     * <p/>
     * Created by <b>Negru Ionut Valentin</b> on <b>20/1/2016</b>.
     */
    public class ToolbarController {
    
        private boolean handleStatusBar = false;
        private boolean showTitle = true;
    
        /**
         * Call this method in onCreate() method of your Activity or in onCreateView() in Fragment
         *
         * @param view
         *         The view into which to look for the toolbar
         * @param activity
         *         The activity for which setup the toolbar
         *
         * @return The toolbar found and customized or {@code null}
         */
        public Toolbar initToolbar(View view, Activity activity) {
            Toolbar mToolbar = (Toolbar) view.findViewById(R.id.toolbar);
    
            // Valid and visible toolbar - otherwise ignore
            if (null != mToolbar && mToolbar.getVisibility() == View.VISIBLE) {
    
                int paddingLeft = mToolbar.getPaddingLeft();
                int paddingRight = mToolbar.getPaddingRight();
                int paddingBottom = mToolbar.getPaddingBottom();
                // Set the top padding of the toolbar to match the status bar height
                int paddingTop = new CynnyContextWrapper(activity).getStatusBarHeight();
    
                mToolbar.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
    
                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
                    ViewParent parent = mToolbar.getParent();
                    if (parent instanceof RelativeLayout) {
                        // Manually create the drop shadow
                        RelativeLayout.LayoutParams params =
                                new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                                                Metrics.convertDpToPixel(4, activity));
    
                        View dropShadow = new View(activity);
                        dropShadow.setBackgroundResource(R.drawable.toolbar_shadow);
    
                        params.addRule(RelativeLayout.BELOW, R.id.toolbar);
    
                        ((RelativeLayout) parent).addView(dropShadow, params);
                    }
                }
    
                if (activity instanceof AppCompatActivity) {
                    // Check if the Activity actually support ActionBar with Toolbar and set our custom Toolbar for it
                    ((AppCompatActivity) activity).setSupportActionBar(mToolbar);
    
                    // Get the actionbar from the activity
                    ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar();
                    if (null != actionBar) {
                        // If the actionbar is valid, customize it
                        actionBar.setDisplayHomeAsUpEnabled(true);
                        actionBar.setHomeButtonEnabled(true);
    
                        actionBar.setDisplayShowTitleEnabled(this.showTitle);
    
                        mToolbar.setNavigationIcon(R.drawable.ic_arrow_back_selector);
                    }
                }
    
                if (this.handleStatusBar) {
                    // For showing the status bar
                    activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
                    activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
                }
            } else if (handleStatusBar) {
                // Force hide the status bar
                activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
                activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
            }
    
            return mToolbar;
        }
    
        /**
         * Set the flag indicating if the controller should handle or not the status bar.
         *
         * @param handleStatusBar
         *         Flag which indicates if the initialization of the toolbar should also update
         *         the status bar state (if two calls are made for the init, the last one will
         *         be taken into consideration).
         *
         * @return The current toolbar controller.
         */
        public ToolbarController setHandleStatusBar(boolean handleStatusBar) {
            this.handleStatusBar = handleStatusBar;
    
            return this;
        }
    
        /**
         * Set the flag indicating if the toolbar should show or hide the title.
         *
         * @param showTitle
         *         Flag indicating if the toolbar should also show the title (the title can be changed after the toolbar
         *         initialization)
         *
         * @return The current toolbar controller.
         */
        public ToolbarController setShowTitle(boolean showTitle) {
            this.showTitle = showTitle;
    
            return this;
        }
    }
    

    In the activity you should use this in onCreate() method like this:

    // Create and customize the Toolbar controller
    new ToolbarController().setHandleStatusBar(true).setShowTitle(true)
                                     .initToolbar(((ViewGroup) findViewById(android.R.id.content)).getChildAt(0),
                                                  this);
    

    In the fragment you should use this in onCreateView() method like this:

    new ToolbarController().setHandleStatusBar(false).setShowTitle(false).initToolbar(resultView, getActivity());
    

    Do not forget to add you toolbar in the layouts and set it's id with android:id="@id/toolbar". If you want to use another id, you can customize the controller and add another setter method which uses the id you provide.

    I have two toolbar layouts created:

    v21

        <!-- This is the new widget added in Lollipop - use with care -->
        <android.support.v7.widget.Toolbar
                android:id="@id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:minHeight="?attr/actionBarSize"
                android:theme="@style/TitleToolbarTheme"
                android:background="?android:attr/colorPrimary"
                android:elevation="@dimen/toolbar_elevation"
                />
    </merge>
    

    other

    <?xml version="1.0" encoding="utf-8"?>
    <merge xmlns:android="http://schemas.android.com/apk/res/android"
            >
    
        <!-- This is the new widget added in Lollipop - use with care -->
        <android.support.v7.widget.Toolbar
                android:id="@id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:minHeight="?attr/actionBarSize"
                android:theme="@style/TitleToolbarTheme"
                android:background="?attr/colorPrimary"
                />
    
    </merge>
    

    I use them in may layouts using:

    <include layout="@layout/toolbar" />
    

    I hope this will help to solve your issue. Also take note this can be optimized further more, but it works for me and I don't want to loose anymore time on this issue.

    0 讨论(0)
提交回复
热议问题