`

自定义Behavior实现AppBarLayout越界弹性效果

阅读更多


一、继承AppBarLayout.Behavior

AppBarLayout有一个默认的Behavior,即AppBarLayout.Behavior,AppBarLayout.Behavior已注解的方式设置给AppBarLayout。

@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
public class AppBarLayout extends LinearLayout {
    ...
}

1.继承AppBarLayout.Behavior自定义Behavior

我们可以继承AppBarLayout.Behavior并重新设置给AppBarLayout来修改AppBarLayout的默认滚动行为,实现AppBarLayout的弹性越界效果就可以通过这种方式实现。

继承AppBarLayout.Behavior需要重写构造方法

public class AppBarLayoutOverScrollViewBehavior extends AppBarLayout.Behavior {

    public AppBarLayoutOverScrollViewBehavior() {
    }

    public AppBarLayoutOverScrollViewBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

}


2.将自定义的Behavior设置给AppBarLayout

可以通过两种方式将自定义的Behavior设置给AppBarLayout

在布局文件中设置

<android.support.design.widget.AppBarLayout
     ...
     app:layout_behavior="packageName.AppBarLayoutOverScrollViewBehavior">
 </android.support.design.widget.AppBarLayout>

在代码中设置

 AppBarLayout appBar = (AppBarLayout) findViewById(R.id.appbar);
 CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
 params.setBehavior(new AppBarLayoutOverScrollViewBehavior());
 appBar.setLayoutParams(params);

设置完成后,自定义的Behavior就会生效,但是因为没有重写任何方法,所以AppBarLayout的滚动行为不会发生变化。

二、Behavior中的回调方法分析

将自定义的Behavior设置给AppBarLayout后,可以在自定义的Behavior中重写滚动相关回调方法

public class AppBarLayoutOverScrollViewBehavior extends AppBarLayout.Behavior {

    ...

    /**
     * AppBarLayout布局时调用
     *
     * @param parent 父布局CoordinatorLayout
     * @param abl 使用此Behavior的AppBarLayout
     * @param layoutDirection 布局方向
     * @return 返回true表示子View重新布局,返回false表示请求默认布局
     */
    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, AppBarLayout abl, int layoutDirection) {
        return super.onLayoutChild(parent, abl, layoutDirection);
    }

    /**
     * 当CoordinatorLayout的子View尝试发起嵌套滚动时调用
     *
     * @param parent 父布局CoordinatorLayout
     * @param child 使用此Behavior的AppBarLayout
     * @param directTargetChild CoordinatorLayout的子View,或者是包含嵌套滚动操作的目标View
     * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
     * @param nestedScrollAxes 嵌套滚动的方向
     * @return 返回true表示接受滚动
     */
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
        return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes);
    }

    /**
     * 当嵌套滚动已由CoordinatorLayout接受时调用
     *
     * @param coordinatorLayout 父布局CoordinatorLayout
     * @param child 使用此Behavior的AppBarLayout
     * @param directTargetChild CoordinatorLayout的子View,或者是包含嵌套滚动操作的目标View
     * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
     * @param nestedScrollAxes 嵌套滚动的方向
     */
    @Override
    public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
        super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
    }

    /**
     * 当准备开始嵌套滚动时调用
     *
     * @param coordinatorLayout 父布局CoordinatorLayout
     * @param child 使用此Behavior的AppBarLayout
     * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
     * @param dx 用户在水平方向上滑动的像素数
     * @param dy 用户在垂直方向上滑动的像素数
     * @param consumed 输出参数,consumed[0]为水平方向应该消耗的距离,consumed[1]为垂直方向应该消耗的距离
     */
    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
    }

    /**
     * 嵌套滚动时调用
     *
     * @param coordinatorLayout 父布局CoordinatorLayout
     * @param child 使用此Behavior的AppBarLayout
     * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
     * @param dxConsumed 由目标View滚动操作消耗的水平像素数
     * @param dyConsumed 由目标View滚动操作消耗的垂直像素数
     * @param dxUnconsumed 由用户请求但是目标View滚动操作未消耗的水平像素数
     * @param dyUnconsumed 由用户请求但是目标View滚动操作未消耗的垂直像素数
     */
    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
    }

    /**
     * 当嵌套滚动的子View准备快速滚动时调用
     *
     * @param coordinatorLayout 父布局CoordinatorLayout
     * @param child 使用此Behavior的AppBarLayout
     * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
     * @param velocityX 水平方向的速度
     * @param velocityY 垂直方向的速度
     * @return 如果Behavior消耗了快速滚动返回true
     */
    @Override
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY) {
        return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
    }

    /**
     * 当嵌套滚动的子View快速滚动时调用
     *
     * @param coordinatorLayout 父布局CoordinatorLayout
     * @param child 使用此Behavior的AppBarLayout
     * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
     * @param velocityX 水平方向的速度
     * @param velocityY 垂直方向的速度
     * @param consumed 如果嵌套的子View消耗了快速滚动则为true
     * @return 如果Behavior消耗了快速滚动返回true
     */
    @Override
    public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) {
        return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
    }

    /**
     * 当定制滚动时调用
     *
     * @param coordinatorLayout 父布局CoordinatorLayout
     * @param abl 使用此Behavior的AppBarLayout
     * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
     */
    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl, View target) {
        super.onStopNestedScroll(coordinatorLayout, abl, target);
    }
}

可以通过打印log来观察AppBarLayout在滚动时Behavior中回调方法的调用情况。

通过观察可以发现:

上滑时
当AppBarLayout由展开到收起时,会依次调用onStartNestedScroll()->onNestedScrollAccepted()->onNestedPreScroll()->onStopNestedScroll()
当AppBarLayout收起后继续向上滑动时,会依次调用onStartNestedScroll()->onNestedScrollAccepted()->onNestedPreScroll()->onNestedScroll()->onStopNestedScroll()
下滑时
当AppBarLayout全部展开时(即未到顶部时),会依次调用onStartNestedScroll()->onNestedScrollAccepted()->onNestedPreScroll()->onNestedScroll()->onStopNestedScroll()
当AppBarLayout全部展开时(即到顶部时),继续向下滑动屏幕,会依次调用onStartNestedScroll()->onNestedScrollAccepted()->onNestedPreScroll()->onNestedScroll()->onStopNestedScroll()
当有快速滑动时会在onStopNestedScroll()前依次调用onNestedPreFling()->onNestedFling()
所以要修改AppBarLayout的越界行为可以重写onNestedPreScroll()或onNestedScroll(),因为AppBarLayout收起时不会调用onNestedScroll(),所以只能选择重写onNestedPreScroll(),具体原因下面会有说明。

三、重写Behavior的相关方法

1.获取越界时需要改变尺寸的View

布局时会调用onLayoutChild(),所以在该方法中可获取需要改变尺寸的View,可以使用View的findViewWithTag方法获取指定的View,并初始化属性。

public class AppBarLayoutOverScrollViewBehavior extends AppBarLayout.Behavior {
    private static final String TAG = "overScroll";
    private View mTargetView;       // 目标View
    private int mParentHeight;      // AppBarLayout的初始高度
    private int mTargetViewHeight;  // 目标View的高度

    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, AppBarLayout abl, int layoutDirection) {
        boolean handled = super.onLayoutChild(parent, abl, layoutDirection);
        // 需要在调用过super.onLayoutChild()方法之后获取
        if (mTargetView == null) {
            mTargetView = parent.findViewWithTag(TAG);
            if (mTargetView != null) {
                initial(abl);
            }
        }
        return handled;
    }

    private void initial(AppBarLayout abl) {
        // 必须设置ClipChildren为false,这样目标View在放大时才能超出布局的范围
        abl.setClipChildren(false);
        mParentHeight = abl.getHeight();
        mTargetViewHeight = mTargetView.getHeight();
    }

    ...

}

需要在布局文件或代码中给目标View指定tag,如下:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:theme="@style/AppTheme.AppBarOverlay"
        android:transitionName="picture"
        app:layout_behavior="com.zly.exifviewer.widget.behavior.AppBarLayoutOverScrollViewBehavior"
        tools:targetApi="lollipop">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsingToolbarLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:contentScrim="@color/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
            app:statusBarScrim="@color/colorPrimaryDark">

            <ImageView
                android:id="@+id/siv_picture"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:fitsSystemWindows="true"
                android:foreground="@drawable/shape_fg_picture"
                android:scaleType="centerCrop"
                android:tag="overScroll"
                app:layout_collapseMode="parallax"
                tools:src="@android:drawable/sym_def_app_icon" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:contentInsetEnd="64dp"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/AppTheme.PopupOverlay" />
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        ...

    </android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>

2.下滑处理

重写onNestedPreScroll()修改AppBarLayou滑动的顶部后的行为

private static final float TARGET_HEIGHT = 500; // 最大滑动距离
private float mTotalDy;     // 总滑动的像素数
private float mLastScale;   // 最终放大比例
private int mLastBottom;    // AppBarLayout的最终Bottom值

@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
    // 1.mTargetView不为null
    // 2.是向下滑动,dy<0表示向下滑动
    // 3.AppBarLayout已经完全展开,child.getBottom() >= mParentHeight
    if (mTargetView != null && dy < 0 && child.getBottom() >= mParentHeight) {
        // 累加垂直方向上滑动的像素数
        mTotalDy += -dy;
        // 不能大于最大滑动距离
        mTotalDy = Math.min(mTotalDy, TARGET_HEIGHT);
        // 计算目标View缩放比例,不能小于1
        mLastScale = Math.max(1f, 1f + mTotalDy / TARGET_HEIGHT);
        // 缩放目标View
        ViewCompat.setScaleX(mTargetView, mLastScale);
        ViewCompat.setScaleY(mTargetView, mLastScale);
        // 计算目标View放大后增加的高度
        mLastBottom = mParentHeight + (int) (mTargetViewHeight / 2 * (mLastScale - 1));
        // 修改AppBarLayout的高度
        child.setBottom(mLastBottom);
    } else {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
    }
}

此时可以实现下滑越界时目标View放大,AppBarLayout变高的效果。

3.上滑处理

下滑时目标View放大,AppBarLayout变高,如果此时用户不松开手指,直接上滑,需要目标View缩小,并且AppBarLayout变高。

默认情况下AppBarLayout的滑动是通过修改top和bottom实现的,所以上滑时,AppBarLayout为整体向上移动,高度不会发生改变,并且AppBarLayout下面的ScrollView也会向上滚动;而我们需要的是在AppBarLayout的高度大于原始高度时,减小AppBarLayout的高度,top不发生改变,并且AppBarLayout下面的ScrollView不会向上滚动。

AppBarLayout上滑时不会调用onNestedScroll(),所以只能在onNestedPreScroll()方法中修改,这也是为什么选择onNestedPreScroll()方法的原因

@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
    if (mTargetView != null && dy < 0 && child.getBottom() >= mParentHeight) {
        ...
    } else 
    // 1.mTargetView不为null
    // 2.是向上滑动,dy>0表示向下滑动
    // 3.AppBarLayout尚未恢复到原始高度child.getBottom() > mParentHeight
    if (mTargetView != null && dy > 0 && child.getBottom() > mParentHeight) {
        // 累减垂直方向上滑动的像素数
        mTotalDy -= dy;
        // 计算目标View缩放比例,不能小于1
        mLastScale = Math.max(1f, 1f + mTotalDy / TARGET_HEIGHT);
        // 缩放目标View
        ViewCompat.setScaleX(mTargetView, mLastScale);
        ViewCompat.setScaleY(mTargetView, mLastScale);
        // 计算目标View缩小后减少的高度
        mLastBottom = mParentHeight + (int) (mTargetViewHeight / 2 * (mLastScale - 1));
        // 修改AppBarLayout的高度
        child.setBottom(mLastBottom);
        // 保持target不滑动
        target.setScrollY(0);
    } else {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
    }
}

与上滑的逻辑基本一直,所以可写为一个方法

@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
    if (mTargetView != null && ((dy < 0 && child.getBottom() >= mParentHeight) || (dy > 0 && child.getBottom() > mParentHeight))) {
        scale(child, target, dy);
    } else {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
    }
}

private void scale(AppBarLayout abl, View target, int dy) {
    mTotalDy += -dy;
    mTotalDy = Math.min(mTotalDy, TARGET_HEIGHT);
    mLastScale = Math.max(1f, 1f + mTotalDy / TARGET_HEIGHT);
    ViewCompat.setScaleX(mTargetView, mLastScale);
    ViewCompat.setScaleY(mTargetView, mLastScale);
    mLastBottom = mParentHeight + (int) (mTargetViewHeight / 2 * (mLastScale - 1));
    abl.setBottom(mLastBottom);
    target.setScrollY(0);
}

4.还原

当AppBarLayout处于越界时,如果用户松开手指,此时应该让目标View和AppBarLayout都还原到原始状态,重写onStopNestedScroll()方法

@Override
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl, View target) {
    recovery(abl);
    super.onStopNestedScroll(coordinatorLayout, abl, target);
}

private void recovery(final AppBarLayout abl) {
    if (mTotalDy > 0) {
        mTotalDy = 0;
        // 使用属性动画还原
        ValueAnimator anim = ValueAnimator.ofFloat(mLastScale, 1f).setDuration(200);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();
                ViewCompat.setScaleX(mTargetView, value);
                ViewCompat.setScaleY(mTargetView, value);
                abl.setBottom((int) (mLastBottom - (mLastBottom - mParentHeight) * animation.getAnimatedFraction()));
            }
        });
        anim.start();
    }
}

5.优化

由于用户在滑动时有可能触发快速滑动,会导致在AppBarLayout收起后触发还原动画,重新修改AppBarLayout的Bottom,从而显示错误,所以当发生快速滑动时需要禁止还原动画,直接还原到初始状态

private boolean isAnimate;  //是否有动画

@Override
public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
    // 开始滑动时,启用动画
    isAnimate = true;
    return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes);
}

@Override
public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY) {
    // 如果触发了快速滚动且垂直方向上速度大于100,则禁用动画
    if (velocityY > 100) {
        isAnimate = false;
    }
    return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
}

private void recovery(final AppBarLayout abl) {
    if (mTotalDy > 0) {
        mTotalDy = 0;
        if (isAnimate) {
            ValueAnimator anim = ValueAnimator.ofFloat(mLastScale, 1f).setDuration(200);
            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    ViewCompat.setScaleX(mTargetView, value);
                    ViewCompat.setScaleY(mTargetView, value);
                    abl.setBottom((int) (mLastBottom - (mLastBottom - mParentHeight) * animation.getAnimatedFraction()));
                }
            });
            anim.start();
        } else {
            ViewCompat.setScaleX(mTargetView, 1f);
            ViewCompat.setScaleY(mTargetView, 1f);
            abl.setBottom(mParentHeight);
        }
    }
}



可以从这里获取代码
  • 大小: 939.3 KB
分享到:
评论

相关推荐

    使AppBarLayout 可以弹性下拉的Behavior.zip

    2. **实现弹性动画效果**:在`onNestedScroll`中计算滑动距离,并根据此距离调整AppBarLayout的高度或透明度,模拟弹簧回弹的效果。这可能需要用到`ViewCompat.animate()`或者自定义动画类来实现。 3. **注册...

    Coordinatorlayout嵌套滑动,自定义Behavior的Demo

    在`3.1.3`这个文件中,可能包含了示例代码、资源文件以及详细的步骤说明,帮助开发者逐步实现自定义`Behavior`的功能。通过学习这个Demo,开发者不仅可以理解`Behavior`的工作原理,还能掌握如何在实际项目中应用它...

    自定义behavior监听控件的滑动事件

    Behavior 类使得我们能够自定义控件的行为,特别是在与 AppBarLayout、FloatingActionButton 等组件配合时,可以实现如抽屉滑动隐藏、底部导航栏随内容滑动而出现等高级交互。 标题"自定义behavior监听控件的滑动...

    appbarlayout-spring-behavior.zip

    AppBarLayout-spring-behavior则是一种特殊的行为(Behavior)实现,它扩展了AppBarLayout的标准滚动行为,使其具有弹簧般的回弹效果,增强了用户体验。 AppBarLayout的行为(Behavior)是Android ...

    自定义Behavior简单教程

    自定义Behavior Demo,可以结合任何View使用,可以自定义动画等!详解请移步严振杰的博客:http://blog.csdn.net/yanzhenjie1003/article/details/52205665

    CoordinatorLayout自定义Behavior

    `CoordinatorLayout` 的核心功能在于它能够协调其子视图之间的行为,通过自定义`Behavior`,开发者可以实现高度定制化的布局动画和交互。这篇博客的文章标题是“CoordinatorLayout自定义Behavior”,显然,它将引导...

    Android自定义Behavior

    BottomSheetBehavior、SwipeDismissBehavior、自定义Behavior等。原理和教程请移步严振杰的博客:http://blog.csdn.net/yanzhenjie1003。

    Android CoordinatorLayout高级用法之自定义Behavior

    上次简单的说了一下...其实它并不是一个字符串资源,而它代表的是一个类,就是一个Behavior,这玩意其实还可以自定义的。 首先,来让我见识一下它的真面目: public static abstract class Behavior&lt;V ex

    Material Design系列之自定义Behavior支持所有View

    一、实现效果图 这个右下角的FAB,动画当然可以多种多样,可以放在界面的任何地方,我们这里只举个例子。但是v7包中提供的Behavior目前只能是FloatingActionButton来用,所以今天我们实现的这个Behavior是支持所有的...

    FlingAppBarLayout,一个自定义的AppBarLayout,可以顺利地抛出.zip

    一个自定义的AppBarLayout,可以顺利地抛出

    Material Design系列之Behavior实现Android知乎首页

    这个效果其实并不难实现,但是它的用处很大,当用户手指上滑,屏幕上显示下方内容的时候,隐藏Toolbar、Tab导航、FAB来腾出更大的空间显示内容,让用户爽。简单粗暴,但这就是我们的目的。 首先就是头部的Toolbar,...

    Android 利用CoordinatorLayout实现高仿抖音个人中心 下拉越界回弹 图片放大

    1. **下拉越界回弹效果**:这是通过` AppBarLayout` 和 `CollapsingToolbarLayout` 实现的。`AppBarLayout`是一个垂直滑动布局,可以与`CoordinatorLayout`配合使用,实现头部视图的滚动效果。`...

    learn-coordinatorlayout-behavior:CoordinatorLayout 自定义Behavior 高仿美团商家详情界面 实现页面内容复杂联动效果

    该项目是为了练习-&gt; 使用CoordinatorLayout.Behavior 实现页面复杂联动效果 代码模仿实现美团商家详情界面内容联动 开发使用知识点顺带涉及到: Scroller+Handler 实现View自动滑动 View属性动画 触摸事件分发机制 ...

    MiMusicBehavior:自定义Behavior实现小米音乐歌手详情页

    在本文中,我们将深入探讨如何使用Java来创建一个名为MiMusicBehavior的自定义Behavior,以此实现类似小米音乐歌手详情页的效果。首先,我们需要理解Behavior的基本概念。 Behavior 是 Android Design Support ...

    Android-Behavior实现的漂亮的效果

    在"Android-Behavior实现的漂亮的效果"这个项目中,BehaviorDemo-master很可能是包含了一系列示例代码,演示了如何使用Behavior来实现各种吸引人的动画效果。这些效果可能包括但不限于: 1. **悬浮按钮...

    自定义behavior

    该源码介绍了如何自定义behavior,可以实现观察者控件监听其它控件状态的变化,从而作出相应的处理。相关博客讲解地址:https://blog.csdn.net/gaoxiaoweiandy/article/details/88089272

    QML自定义电池充电/电量显示效果

    在压缩包文件`battery`中,可能包含了实现上述效果的QML源代码示例,包括Battery.qml文件,里面可能有自定义电池元件的定义,以及main.qml文件,展示如何在主应用中使用这个自定义元件。通过查看和学习这些代码,你...

    Android自定义行为Behavior的代码例子

    Android自定义行为Behavior的代码例子。用于演示在CoordinatorLayout中,通过自定义Behavior实现两个控件实时互动的功能,包括:侧滑删除视图、女孩照镜子、定滑轮升降三种动画效果。

    用behavior实现recyclerView的下拉加载更多,水波纹效果

    在本项目中,我们将探讨如何使用自定义的`Behavior`来实现RecyclerView的下拉加载更多功能,并结合水波纹效果,赋予用户更丰富的交互体验。 首先,`Behavior`是Android Design Support Library中的一个关键组件,它...

    Android-使用AppBarLayout与CoordinatorLayout高仿稀土掘金

    例如,我们可以通过自定义Behavior来控制AppBarLayout的滑动行为,使其在内容滚动时产生相应的动画效果。这对于实现类似稀土掘金那样流畅的用户体验至关重要。 **实现高仿步骤** 1. **创建布局文件**:首先,在...

Global site tag (gtag.js) - Google Analytics