`

AppBarLayout.OnOffsetChangedListener的使用

阅读更多
如果没听说过AppBarLayout.OnOffsetChangedListener,那么就先看这里:
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0616/3052.html

我在项目中的使用:
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.support.annotation.NonNull;
import android.support.design.widget.AppBarLayout;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * CollapsingAvatarToolbar必须在AppBarLayout里面,被CollapsingToolbarLayout包裹。
	CollapsingAvatarToolbar必须有个Toolbar伴随,如果你不想使用Toolbar,我们可以讨论讨论。
	扩展高度(Expanded height) 取决于AppBarLayout的高度。
	折叠高度(Collapsed height )取决于Toolbar的高度。
	你必须在CollapsingAvatarToolbar里面设置头像(avatar)和标题视图( title view),且id必须喝上面演示的完全一致。这些id事library里面的。(所以是@而不是@+)。
	你可以使用任意TextView作为title,以及任意view作为头像,我这里的例子用的是hdodenhof的CircleImageView ,但是这取决于你自己。
	你也可以添加更多view到CollapsingAvatarToolbar里面。
	所有的自定义属性都是可选的,如果没有提供就使用默认的 。
 * @author Administrator
 *	@see http://www.jcodecraeer.com/a/opensource/2015/0830/3385.html
 */
public class CollapsingAvatarToolbar extends LinearLayout implements AppBarLayout.OnOffsetChangedListener {

    private View avatarView;
    private TextView titleView;

    private float collapsedPadding;
    private float expandedPadding;

    private float expandedImageSize;
    private float collapsedImageSize;

    private float collapsedTextSize;
    private float expandedTextSize;

    private boolean valuesCalculatedAlready = false;
    private Toolbar toolbar;
    private AppBarLayout appBarLayout;
    private float collapsedHeight;
    private float expandedHeight;
    private float maxOffset;

    public CollapsingAvatarToolbar(Context context) {
        this(context, null);
        init();
    }

    public CollapsingAvatarToolbar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();

        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CollapsingAvatarToolbar, 0, 0);

        try {
            collapsedPadding = a.getDimension(R.styleable.CollapsingAvatarToolbar_collapsedPadding, -1);
            expandedPadding = a.getDimension(R.styleable.CollapsingAvatarToolbar_expandedPadding, -1);

            collapsedImageSize = a.getDimension(R.styleable.CollapsingAvatarToolbar_collapsedImageSize, -1);
            expandedImageSize = a.getDimension(R.styleable.CollapsingAvatarToolbar_expandedImageSize, -1);

            collapsedTextSize = a.getDimension(R.styleable.CollapsingAvatarToolbar_collapsedTextSize, -1);
            expandedTextSize = a.getDimension(R.styleable.CollapsingAvatarToolbar_expandedTextSize, -1);
        } finally {
            a.recycle();
        }

        final Resources resources = getResources();
        if (collapsedPadding < 0) {
            collapsedPadding = resources.getDimension(R.dimen.default_collapsed_padding);
        }
        if (expandedPadding < 0) {
            expandedPadding = resources.getDimension(R.dimen.default_expanded_padding);
        }
        if (collapsedImageSize < 0) {
            collapsedImageSize = resources.getDimension(R.dimen.default_collapsed_image_size);
        }
        if (expandedImageSize < 0) {
            expandedImageSize = resources.getDimension(R.dimen.default_expanded_image_size);
        }
        if (collapsedTextSize < 0) {
            collapsedTextSize = resources.getDimension(R.dimen.default_collapsed_text_size);
        }
        if (expandedTextSize < 0) {
            expandedTextSize = resources.getDimension(R.dimen.default_expanded_text_size);
        }
    }

    private void init() {
        setOrientation(HORIZONTAL);
    }

    @NonNull
    private AppBarLayout findParentAppBarLayout() {
        ViewParent parent = this.getParent();
        if (parent instanceof AppBarLayout) {
            return ((AppBarLayout) parent);
        } else if (parent.getParent() instanceof AppBarLayout) {
            return ((AppBarLayout) parent.getParent());
        } else {
            throw new IllegalStateException("Must be inside an AppBarLayout"); 
            //TODO actually, a collapsingtoolbar
        }
    }

    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        findViews();
        if (!isInEditMode()) {
            appBarLayout.addOnOffsetChangedListener(this);
        } else {
            setExpandedValuesForEditMode();
        }
    }

    private void setExpandedValuesForEditMode() {
        calculateValues();
        updateViews(1f, 0);
    }

    private void findViews() {
        appBarLayout = findParentAppBarLayout();
        toolbar = findSiblingToolbar();
        avatarView = findAvatar();
        titleView = findTitle();
    }

    @NonNull
    private View findAvatar() {
        View avatar = this.findViewById(R.id.cat_avatar);
        if (avatar == null) {
            throw new IllegalStateException("View with id ta_avatar not found");
        }
        return avatar;
    }

    @NonNull
    private TextView findTitle() {
        TextView title = (TextView) this.findViewById(R.id.cat_title);
        if (title == null) {
            throw new IllegalStateException("TextView with id ta_title not found");
        }
        return title;
    }

    @NonNull
    private Toolbar findSiblingToolbar() {
        ViewGroup parent = ((ViewGroup) this.getParent());
        for (int i = 0, c = parent.getChildCount(); i < c; i++) {
            View child = parent.getChildAt(i);
            if (child instanceof Toolbar) {
                return (Toolbar) child;
            }
        }
        throw new IllegalStateException("No toolbar found as sibling");
    }

    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int offset) {
        if (!valuesCalculatedAlready) {
            calculateValues();
            valuesCalculatedAlready = true;
        }
        float expandedPercentage = 1 - (-offset / maxOffset);
        updateViews(expandedPercentage, offset);
    }

    private void calculateValues() {
        collapsedHeight = toolbar.getHeight();
        expandedHeight = appBarLayout.getHeight() - toolbar.getHeight();
        maxOffset = expandedHeight;
    }

    private void updateViews(float expandedPercentage, int currentOffset) {
        float inversePercentage = 1 - expandedPercentage;
        float translation = -currentOffset + ((float) toolbar.getHeight() * expandedPercentage);

        float currHeight = collapsedHeight + (expandedHeight - collapsedHeight) * expandedPercentage;
        float currentPadding = expandedPadding + (collapsedPadding - expandedPadding) * inversePercentage;
        float currentImageSize = collapsedImageSize + (expandedImageSize - collapsedImageSize) * expandedPercentage;
        float currentTextSize = collapsedTextSize + (expandedTextSize - collapsedTextSize) * expandedPercentage;

        setContainerOffset(translation);
        setContainerHeight((int) currHeight);
        setPadding((int) currentPadding);
        setAvatarSize((int) currentImageSize);
        setTextSize(currentTextSize);
    }

    private void setContainerOffset(float translation) {
        this.setTranslationY(translation);
    }

    private void setContainerHeight(int currHeight) {
        this.getLayoutParams().height = currHeight;
    }

    private void setPadding(int currentPadding) {
        this.setPadding(currentPadding, 0, 0, 0);
    }

    private void setTextSize(float currentTextSize) {
        titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, currentTextSize);
    }

    private void setAvatarSize(int currentImageSize) {
        avatarView.getLayoutParams().height = currentImageSize;
        avatarView.getLayoutParams().width = currentImageSize;
    }
}

attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    
    <declare-styleable name="CollapsingAvatarToolbar">
        <attr name="collapsedPadding" format="dimension" />
        <attr name="expandedPadding" format="dimension" />
        <attr name="collapsedImageSize" format="dimension" />
        <attr name="expandedImageSize" format="dimension" />
        <attr name="collapsedTextSize" format="dimension" />
        <attr name="expandedTextSize" format="dimension" />
    </declare-styleable>

</resources>

ids.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="cat_avatar" type="id"></item>
    <item name="cat_title" type="id"></item>
</resources>


使用,伪代码:
<android.support.design.widget.AppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:fitsSystemWindows="true"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" >

            <!-- 如果想制造toolbar的折叠效果,我们必须把Toolbar放在CollapsingToolbarLayout中: -->
            <!-- 通常,我们我们都是设置Toolbar的title,而现在,我们需要把title设置在CollapsingToolBarLayout上,而不是Toolbar。 -->
            <!-- 给需要有折叠效果的组件设置 layout_collapseMode属性 -->
            <!-- Toolbar 的高度layout_height必须固定,不能 “wrap_content”,否则Toolbar不会滑动,也没有折叠效果 -->
			<!-- app:contentScrim="?attr/colorPrimary"用于设置收缩的时候Toolbar自动变化到普通的颜色 -->
			<!-- app:titleEnabled="false"用于设置是否显示title,默认为显示-->
            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/collapsingToolbarLayout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_scrollFlags="scroll|exitUntilCollapsed"
                android:fitsSystemWindows="true"
                app:contentScrim="?attr/colorPrimary"
                app:expandedTitleMarginEnd="64dp"
                app:expandedTitleMarginStart="48dp" 
                app:titleEnabled="false"
                >

                <!-- 制造视差效果 -->
                <!-- CollapsingToolbarLayout还能让我们做出更高级的动画,比如在里面放一个ImageView,然后在它折叠的时候渐渐淡出。同时在用户滚动的时候title的高度也会随着改变。 -->
                <!-- 为了制造出这种效果,我们添加一个定义了app:layout_collapseMode="parallax" 属性的ImageView。 -->

                <ImageView
                    android:id="@+id/backdrop"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    app:layout_collapseMode="parallax"
                    app:layout_collapseParallaxMultiplier="0.7"
                    app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
                    android:fitsSystemWindows="true"
                    android:scaleType="centerCrop"
                    android:src="@drawable/bg_login" />

                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_collapseMode="pin"
                    app:layout_scrollFlags="scroll|enterAlways"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Dark"
                    app:titleTextAppearance="@style/TextAppearance.AppCompat.Headline" />
                
                <com.widget.view.CollapsingAvatarToolbar
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    android:gravity="center_vertical"
                    >
                    <!-- 
                    app:collapsedPadding="@dimen/collapsedPadding"
					  app:expandedPadding="@dimen/expandedPadding"
					  app:collapsedImageSize="@dimen/collapsedImageSize"
					  app:expandedImageSize="@dimen/expandedImageSize"
					  app:collapsedTextSize="@dimen/collapsedTextSize"
					  app:expandedTextSize="@dimen/expandedTextSize"
                     -->

                    <ImageView
                        android:id="@id/cat_avatar"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:src="@drawable/face" 
                        android:background="@drawable/default_face_bg"
       					 android:padding="4dp"
                        />

                    <TextView
                        android:id="@id/cat_title"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textColor="@android:color/holo_blue_dark"
                        android:text="Name" />
                </com.widget.view.CollapsingAvatarToolbar>
                
            </android.support.design.widget.CollapsingToolbarLayout>
        </android.support.design.widget.AppBarLayout>


https://github.com/hugeterry/CoordinatorTabLayout
分享到:
评论

相关推荐

    Android 仿Toolbar动画显示隐藏.zip

    通常,我们可以使用` AppBarLayout.OnOffsetChangedListener`来监听Toolbar的滑动状态。当偏移量达到一定程度时,可以切换Toolbar的可见性。 ```java AppBarLayout appBarLayout = findViewById(R.id.app_bar_...

    [网盘]AppBarLayout实现上滑隐藏ToolBar.2018_03_19

    这种效果可以通过使用 `AppBarLayout` 来实现。 #### 一、什么是 AppBarLayout `AppBarLayout` 是 Android Support Design 库中的一个重要组件,用于创建应用顶部区域的各种布局,如 Toolbar、Tab Layout 等。它...

    CollapsingToolbarLayout实现翻转的toolbar

    appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { float percentage = (float...

    Toolbar、TabLayout、AppBarLayout和RecyclerView组合可以滑动收起或显示Toolbar的demo

    5. **可滑动收起或显示Toolbar**:这种交互模式是通过实现 AppBarLayout.OnOffsetChangedListener 或使用 CoordinatorLayout 的行为(Behavior)来实现的。当RecyclerView滚动时,监听器会接收到滚动距离的变化,...

    Android用CoordinatorLayout实现Toolbar隐藏和折叠

    6. **动态控制**:在代码中,我们还可以通过调用`AppBarLayout`的`setExpanded()`方法来手动控制`Toolbar`的展开和折叠状态,或者监听` AppBarLayout.OnOffsetChangedListener`事件来响应`Toolbar`位置的变化。...

    标题栏随着滑动渐变

    通过监听` AppBarLayout.OnOffsetChangedListener`的`onOffsetChanged`方法,根据滑动距离动态改变`GradientDrawable`的颜色值,从而实现标题栏颜色的渐变。 在iOS开发中,我们可以利用`UIScrollView`的`...

    浮动layout滑动到顶部悬停效果

    2. **设置滚动监听**:使用` AppBarLayout.OnOffsetChangedListener`监听`AppBarLayout`的滚动状态。当偏移量为0时,表示`AppBarLayout`已完全展开,此时浮动布局位于顶部;当偏移量不为0时,表示`AppBarLayout`正在...

    Android 实现酷炫的顶部栏

    通过监听` AppBarLayout.OnOffsetChangedListener`,可以获取到顶部栏的偏移量,进而实现自定义的动画效果。 在实践中,`AppBarLayout`通常与`NestedScrollView`或`RecyclerView`等滚动视图配合使用,以实现滑动...

    Android实现了仿百度贴吧的悬浮式顶部和底部标题栏的效果.zip

    1. 监听滚动事件:对于`CoordinatorLayout`,可以使用` AppBarLayout.OnOffsetChangedListener`;对于自定义ScrollView,需要重写`onScrollChanged()`方法。 2. 动画处理:当标题栏需要改变位置时,应使用平滑的...

    详解Android使用CoordinatorLayout+AppBarLayout实现拉伸顶部图片功能

    appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { // 实现滑动效果 } }); ``...

    自定义Viewpager

    最后,为了使`ViewPager`与`CollapsingToolbarLayout`的滑动交互更加顺畅,我们需要在`AppBarLayout.OnOffsetChangedListener`中监听`AppBarLayout`的位移变化,以便根据当前状态调整`ViewPager`的行为。 这个项目...

    CollapsingToolbarLayout折叠效果

    3. **展开/折叠状态**:CollapsingToolbarLayout可以监听其展开和折叠的状态,开发者可以通过` AppBarLayout.OnOffsetChangedListener`接口来获取当前的折叠百分比,从而实现自定义的动画效果。 4. **标题处理**:...

    Android-自定义Android平台的状态栏

    这通常需要自定义布局滚动监听器,例如使用`CoordinatorLayout`配合`AppBarLayout`时,可以通过` AppBarLayout.OnOffsetChangedListener`接口实现。 3. **黑色字体**:对于支持暗色主题的设备,我们可能希望在透明...

    CollapsingToolbarLayout折叠toolbar的使用说明

    在实际项目中,开发者可以通过监听` AppBarLayout.OnOffsetChangedListener`事件来获取折叠状态的变化,从而实现更多自定义功能。此外,`CollapsingToolbarLayout`还支持与`TabLayout`结合,创建出带有折叠标题和...

    CollapsingToolbarLayout

    `CollapsingToolbarLayout`通常与`AppBarLayout`一起使用,`AppBarLayout`是一种垂直方向的`LinearLayout`,可以监听滑动事件,常用来管理顶部的工具栏和状态栏。当用户在`NestedScrollView`或`RecyclerView`等可...

    高仿支付宝首页标题栏沉浸式

    可以使用`OnOffsetChangedListener`或`addOnOffsetChangedListener`方法监听`AppBarLayout`的滑动状态变化,以便在标题栏完全隐藏或显示时执行相应操作,比如更改其他视图的状态。 6. **自定义动画** 如果需要更...

    android-material-design:实施一些材料设计效果

    recyclerView.addOnScrollListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { if (Math.abs(verticalOffset) == ...

Global site tag (gtag.js) - Google Analytics