Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b18068a0 authored by Mill Chen's avatar Mill Chen
Browse files

Fix a flicker problem on top app bar

The height of top app bar area is dependent on the line count of title.
This mechanism is always triggered when entering either subsetting page
or rotating the screen, regardless the state of collapsing toolbar. That
is saying this mechanism caused a flicker problem or a title in wrong
color. The mechanism will be updated to check the state of collapsing
toolbar to make sure that it is only triggered if the collapsing toolbar
is in expanded state.

This changes also added null checker to app bar since there's no
AppBarLayout existing in the older version of Android.

Fix: 186419089
Fix: 187709056
Fix: 191746368
Test: visual verified
1) Navigate to a subsetting page with multiline title
2) Rotate the screen to landscape mode and collapse the title
3) Rotate the screen to portrait mode and see if the title is in
collapsing state

Change-Id: Ica868245e0b0a799f76b7f953c606c8e543375f6
parent 144bb33a
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@
        android:background="?android:attr/colorPrimary"
        android:theme="@style/Theme.CollapsingToolbar.Settings">

        <com.android.settingslib.collapsingtoolbar.AdjustableToolbarLayout
        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="@dimen/toolbar_one_line_height"
@@ -59,7 +59,7 @@
                android:transitionName="shared_element_view"
                app:layout_collapseMode="pin"/>

        </com.android.settingslib.collapsingtoolbar.AdjustableToolbarLayout>
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>

    <FrameLayout
+0 −80
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settingslib.collapsingtoolbar;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.google.android.material.appbar.CollapsingToolbarLayout;

/**
 * A customized version of CollapsingToolbarLayout that can apply different font size based on the
 * line count of its title.
 */
public class AdjustableToolbarLayout extends CollapsingToolbarLayout {

    private static final int TOOLBAR_MAX_LINE_NUMBER = 2;

    public AdjustableToolbarLayout(@NonNull Context context) {
        this(context, null);

    }

    public AdjustableToolbarLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AdjustableToolbarLayout(@NonNull Context context, @Nullable AttributeSet attrs,
            int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initCollapsingToolbar();
    }

    @SuppressWarnings("RestrictTo")
    private void initCollapsingToolbar() {
        this.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom,
                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
                v.removeOnLayoutChangeListener(this);
                final int count = getLineCount();
                if (count > TOOLBAR_MAX_LINE_NUMBER) {
                    final ViewGroup.LayoutParams lp = getLayoutParams();
                    lp.height = getResources()
                            .getDimensionPixelSize(R.dimen.toolbar_three_lines_height);
                    setScrimVisibleHeightTrigger(
                            getResources().getDimensionPixelSize(
                                    R.dimen.scrim_visible_height_trigger_three_lines));
                    setLayoutParams(lp);
                } else if (count == TOOLBAR_MAX_LINE_NUMBER) {
                    final ViewGroup.LayoutParams lp = getLayoutParams();
                    lp.height = getResources()
                            .getDimensionPixelSize(R.dimen.toolbar_two_lines_height);
                    setScrimVisibleHeightTrigger(
                            getResources().getDimensionPixelSize(
                                    R.dimen.scrim_visible_height_trigger_two_lines));
                    setLayoutParams(lp);
                }
            }
        });
    }
}
+79 −1
Original line number Diff line number Diff line
@@ -35,10 +35,18 @@ import com.google.android.material.resources.TextAppearanceConfig;
 * A base Activity that has a collapsing toolbar layout is used for the activities intending to
 * enable the collapsing toolbar function.
 */
public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity {
public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity implements
        AppBarLayout.OnOffsetChangedListener {

    private static final int TOOLBAR_MAX_LINE_NUMBER = 2;
    private static final int FULLY_EXPANDED_OFFSET = 0;
    private static final String KEY_IS_TOOLBAR_COLLAPSED = "is_toolbar_collapsed";

    @Nullable
    private CollapsingToolbarLayout mCollapsingToolbarLayout;
    @Nullable
    private AppBarLayout mAppBarLayout;
    private boolean mIsToolbarCollapsed;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -48,6 +56,12 @@ public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity {
        super.setContentView(R.layout.collapsing_toolbar_base_layout);
        mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
        mAppBarLayout = findViewById(R.id.app_bar);
        mAppBarLayout.addOnOffsetChangedListener(this);
        if (savedInstanceState != null) {
            mIsToolbarCollapsed = savedInstanceState.getBoolean(KEY_IS_TOOLBAR_COLLAPSED);
        }

        initCollapsingToolbar();
        disableCollapsingToolbarLayoutScrollingBehavior();

        final Toolbar toolbar = findViewById(R.id.action_bar);
@@ -107,14 +121,43 @@ public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity {
        return true;
    }

    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int offset) {
        if (offset == FULLY_EXPANDED_OFFSET) {
            mIsToolbarCollapsed = false;
        } else {
            mIsToolbarCollapsed = true;
        }
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        if (isChangingConfigurations()) {
            outState.putBoolean(KEY_IS_TOOLBAR_COLLAPSED, mIsToolbarCollapsed);
        }
    }

    /**
     * Returns an instance of collapsing toolbar.
     */
    @Nullable
    public CollapsingToolbarLayout getCollapsingToolbarLayout() {
        return mCollapsingToolbarLayout;
    }

    /**
     * Return an instance of app bar.
     */
    @Nullable
    public AppBarLayout getAppBarLayout() {
        return mAppBarLayout;
    }

    private void disableCollapsingToolbarLayoutScrollingBehavior() {
        if (mAppBarLayout == null) {
            return;
        }
        final CoordinatorLayout.LayoutParams params =
                (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
        final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
@@ -127,4 +170,39 @@ public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity {
                });
        params.setBehavior(behavior);
    }

    @SuppressWarnings("RestrictTo")
    private void initCollapsingToolbar() {
        if (mCollapsingToolbarLayout == null || mAppBarLayout == null) {
            return;
        }
        mCollapsingToolbarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom,
                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
                v.removeOnLayoutChangeListener(this);
                if (mIsToolbarCollapsed) {
                    return;
                }
                final int count = mCollapsingToolbarLayout.getLineCount();
                if (count > TOOLBAR_MAX_LINE_NUMBER) {
                    final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
                    lp.height = getResources()
                            .getDimensionPixelSize(R.dimen.toolbar_three_lines_height);
                    mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(
                            getResources().getDimensionPixelSize(
                                    R.dimen.scrim_visible_height_trigger_three_lines));
                    mCollapsingToolbarLayout.setLayoutParams(lp);
                } else if (count == TOOLBAR_MAX_LINE_NUMBER) {
                    final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
                    lp.height = getResources()
                            .getDimensionPixelSize(R.dimen.toolbar_two_lines_height);
                    mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(
                            getResources().getDimensionPixelSize(
                                    R.dimen.scrim_visible_height_trigger_two_lines));
                    mCollapsingToolbarLayout.setLayoutParams(lp);
                }
            }
        });
    }
}
+95 −1
Original line number Diff line number Diff line
@@ -25,21 +25,31 @@ import android.widget.Toolbar;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.Fragment;

import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;

/**
 * A base fragment that has a collapsing toolbar layout for enabling the collapsing toolbar design.
 */
public abstract class CollapsingToolbarBaseFragment extends Fragment {
public abstract class CollapsingToolbarBaseFragment extends Fragment implements
        AppBarLayout.OnOffsetChangedListener {

    private static final int TOOLBAR_MAX_LINE_NUMBER = 2;
    private static final int FULLY_EXPANDED_OFFSET = 0;
    private static final String KEY_IS_TOOLBAR_COLLAPSED = "is_toolbar_collapsed";

    @Nullable
    private CollapsingToolbarLayout mCollapsingToolbarLayout;
    @Nullable
    private AppBarLayout mAppBarLayout;
    @NonNull
    private Toolbar mToolbar;
    @NonNull
    private FrameLayout mContentFrameLayout;
    private boolean mIsToolbarCollapsed;

    @Nullable
    @Override
@@ -48,6 +58,13 @@ public abstract class CollapsingToolbarBaseFragment extends Fragment {
        final View view = inflater.inflate(R.layout.collapsing_toolbar_base_layout, container,
                false);
        mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar);
        mAppBarLayout = view.findViewById(R.id.app_bar);
        mAppBarLayout.addOnOffsetChangedListener(this);
        if (savedInstanceState != null) {
            mIsToolbarCollapsed = savedInstanceState.getBoolean(KEY_IS_TOOLBAR_COLLAPSED);
        }
        initCollapsingToolbar();
        disableCollapsingToolbarLayoutScrollingBehavior();
        mToolbar = view.findViewById(R.id.action_bar);
        mContentFrameLayout = view.findViewById(R.id.content_frame);
        return view;
@@ -60,6 +77,31 @@ public abstract class CollapsingToolbarBaseFragment extends Fragment {
        requireActivity().setActionBar(mToolbar);
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        if (getActivity().isChangingConfigurations()) {
            outState.putBoolean(KEY_IS_TOOLBAR_COLLAPSED, mIsToolbarCollapsed);
        }
    }

    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int offset) {
        if (offset == FULLY_EXPANDED_OFFSET) {
            mIsToolbarCollapsed = false;
        } else {
            mIsToolbarCollapsed = true;
        }
    }

    /**
     * Return an instance of app bar.
     */
    @Nullable
    public AppBarLayout getAppBarLayout() {
        return mAppBarLayout;
    }

    /**
     * Return the collapsing toolbar layout.
     */
@@ -75,4 +117,56 @@ public abstract class CollapsingToolbarBaseFragment extends Fragment {
    public FrameLayout getContentFrameLayout() {
        return mContentFrameLayout;
    }

    private void disableCollapsingToolbarLayoutScrollingBehavior() {
        if (mAppBarLayout == null) {
            return;
        }
        final CoordinatorLayout.LayoutParams params =
                (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
        final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
        behavior.setDragCallback(
                new AppBarLayout.Behavior.DragCallback() {
                    @Override
                    public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
                        return false;
                    }
                });
        params.setBehavior(behavior);
    }

    @SuppressWarnings("RestrictTo")
    private void initCollapsingToolbar() {
        if (mCollapsingToolbarLayout == null || mAppBarLayout == null) {
            return;
        }
        mCollapsingToolbarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom,
                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
                v.removeOnLayoutChangeListener(this);
                if (mIsToolbarCollapsed) {
                    return;
                }
                final int count = mCollapsingToolbarLayout.getLineCount();
                if (count > TOOLBAR_MAX_LINE_NUMBER) {
                    final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
                    lp.height = getResources()
                            .getDimensionPixelSize(R.dimen.toolbar_three_lines_height);
                    mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(
                            getResources().getDimensionPixelSize(
                                    R.dimen.scrim_visible_height_trigger_three_lines));
                    mCollapsingToolbarLayout.setLayoutParams(lp);
                } else if (count == TOOLBAR_MAX_LINE_NUMBER) {
                    final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
                    lp.height = getResources()
                            .getDimensionPixelSize(R.dimen.toolbar_two_lines_height);
                    mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(
                            getResources().getDimensionPixelSize(
                                    R.dimen.scrim_visible_height_trigger_two_lines));
                    mCollapsingToolbarLayout.setLayoutParams(lp);
                }
            }
        });
    }
}