AppBarLayout+CollapsingToolbarLayout实现自定义工具栏折叠效果_百 ...
2023年7月13日发(作者:)
AppBarLayout+CollapsingToolbarLayout实现⾃定义⼯具栏折叠效果这⼀看不就是跟Material Design⼯具栏折叠效果类似。我们捋⼀下效果是怎样的,滑动的时候实现搜索栏渐变以及⾼度改变的⼯具栏折叠效果###准备⼯作####相关控件了解在创建activity的时候,android studio提供了⼀个叫ScrollingActivity的模版点击创建后之后出现⼀个有⼯具栏折叠效果的activity。ScrollActivity的布局代码如下: AppBarLayout是⼀种⽀持响应滚动⼿势的app bar布局(⽐如⼯具栏滚出或滚⼊屏幕),CollapsingToolbarLayout则是专门⽤来实现⼦布局内不同元素响应滚动细节的布局。与AppBarLayout组合的滚动布局(Recyclerview、NestedScrollView等)需要设置app:layout_behavior这个属性没有设置的话,AppBarLayout将不会响应滚动布局的滚动事件。CollapsingToolbarLayout和ScrollView⼀起使⽤会有滑动bug,注意要使⽤NestedScrollView来替代ScrollView。AppBarLayout的⼦布局有5种滚动标识(就是上⾯代码CollapsingToolbarLayout中配置的app:layout_scrollFlags属性):1. scroll:将此布局和滚动时间关联。这个标识要设置在其他标识之前,没有这个标识则布局不会滚动且其他标识设置⽆效。2. enterAlways:任何向下滚动操作都会使此布局可见。这个标识通常被称为“快速返回”模式。3. enterAlwaysCollapsed:假设你定义了⼀个最⼩⾼度(minHeight)同时enterAlways也定义了,那么view将在到达这个最⼩⾼度的时候开始显⽰,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完。4. exitUntilCollapsed:当你定义了⼀个minHeight,此布局将在滚动到达这个最⼩⾼度的时候折叠。5. snap:当⼀个滚动事件结束,如果视图是部分可见的,那么它将被滚动到收缩或展开。例如,如果视图只有底部25%显⽰,它将折叠。相反,如果它的底部75%可见,那么它将完全展开。CollapsingToolbarLayout可以通过app:contentScrim设置折叠时⼯具栏布局的颜⾊,通过app:statusBarScrim设置折叠时状态栏的颜⾊。默认contentScrim是colorPrimary的⾊值,statusBarScrim是colorPrimaryDark的⾊值。CollapsingToolbarLayout的⼦布局有3种折叠模式(Toolbar中设置的app:layout_collapseMode)1. off:这个是默认属性,布局将正常显⽰,没有折叠的⾏为。2. pin:CollapsingToolbarLayout折叠后,此布局将固定在顶部。3. parallax:CollapsingToolbarLayout折叠时,此布局也会有视差折叠效果。当CollapsingToolbarLayout的⼦布局设置了parallax模式时,我们还可以通过app:layout_collapseParallaxMultiplier设置视差滚动因⼦,值为:0~1。FloatingActionButton这个控件通过app:layout_anchor这个设置锚定在了AppBarLayout下⽅。FloatingActionButton源码中有⼀个Behavior⽅法,当AppBarLayout收缩时,FloatingActionButton就会跟着做出相应变化。了解这么多 ⼤家可以新建个ScrollActivity模版去玩下这些属性####接下来还有⼀个问题就是————⼯具栏的折叠以及展开的状态如何监听?从上⾯知道CollapsingToolbarLayout 是负责折叠⼯具栏的布局,AppBarLayout是负责素响应滚动细节的布局。 那么它们是如何实现联动的?查看AppBarLayout的源码可以看到有这样的⼀个接⼝OnOffsetChangedListerner这个接⼝就是监听当布局AppBarLayout 出现滑动时响应的事件。⽽CollapsingToolbarLayout 持有这个OnOffsetChangedListerner监听对象这样我们可以看出当AppBarLayout出现滑动时,CollapsingToolbarLayou通过OnOffsetChangedListerner这个对象去响应AppBarLayout的滑动,做出对应⼯具栏的状态####使⽤OnOffsetChangedListerner 代码如下:其中⾥⾯offsetChanged ⾥第⼆个参数verticalOffset含义指的是垂直滑动的距离 当滑动时我们打印看下verticalOffset的值向上滑动得到的值是负的,初始值为0 就是展开状态。这⾥我们需要注意的是verticalOffset能滑动最远距离为,AppBarLayout的⾼度 减去 CollapsingToolbarLayout折叠时的⾼度(这⾥AppBarLayout可以通过layout_scrollFlags控制CollapsingToolbarLayout设置显⽰或者隐藏状态)注意:在AppBarLayout 中设置android:fitsSystemWindows="true"这个属性回影响verticalOffset最终的值,会加上状态栏的⾼度⾄此,终于熟悉折叠⼯具栏的效果时如何实现的,接下来就可以根据上⾯的原理去实现⾃定义的⼯具栏。###实现⾃定义折叠⼯具栏⾸先看下我根据上⾯的原理实现的效果:####效果分析 当我们滑动时搜索框背景出现透明的渐变⾼度逐渐变⼩⾄到跟toolbar⼯具栏⾼度⼀致搜索框逐渐往上移动到最顶点####思路分析如何给搜索框背景出现透明渐变?我们知道view有个设置透明值的⽅法 setAlpha(). 参数为 0f到1.0f。 滑动时这个值如何确定,在上⾯我们提到过AppBarLayout ⾥有OnOffsetChangedListerner这个滑动监听。通过这个⽅法获取到 滑动距离verticalOffset 除以 能滑动的总距离 得出 渐变值。如何给搜索框设置⾼度渐变1.⾸先确定搜索框的⾼度渐变成⼯具栏toolbar 渐变百分⽐差值。llHeightOffScale = 1.0f - (toolBarHeight / llHeight)rHeight 指的是⼯具栏toolBar的⾼度 llHeight是指搜索框布局的⾼度。每次滑动时得到的渐变差值为:滑动渐变差值/llHeightOffScale = 滑动距离(verticalOffset)/ 能滑动总距离求出滑动时搜索框对应⾼度缩放指float llHeightScale = 1.0f-(llHeightOffScale*((-verticalOffset)/offSetHeight));3.得出⾼度 = (int)(llHeight* llHeightScale);如何设置搜索框布局位移渐变这⾥我是通过滑动时设置搜索框布局的margin来改变(也可以通过调⽤view的setTranslationY来变化Y轴距离)1.通过LayoutParams获取topMargin值//得到滑动差值 就是布局marginTopllOffDistance = gin;2.计算出每次滑动时marginTop的值,并设置搜索框布局滑动时的距离/总的滑动差值llOffDistance = 滑动距离/能滑动总距离根据这个计算出滑动时的marginTop值float distance = llOffDistance - (-verticalOffset)*llOffDistance / offSetHeight;3.设置给搜索框布局gins(0,(int)distance,0,0);//重新布局⼦控件tLayout();下⾯给出布局代码以及Activity代码: Activity代码public class TestScrollActivity extends AppCompatActivity { private float totalHeight; //总⾼度 private float toolBarHeight; //toolBar⾼度 private float offSetHeight; //总⾼度 - toolBar⾼度 布局位移值 private float llHeight; //搜索框⾼度 private float llHeightOffScale; //⾼度差⽐值 private float llOffDistance; //距离差 private float llOffDistanceScale; //距离差⽐值 private Params params; @BindView(r) Toolbar toolbar; @BindView(r_layout) CollapsingToolbarLayout toolbarLayout; @BindView(_bar) AppBarLayout appBar; @BindView() EditText fab; @BindView() RelativeLayout ll; @BindView() TextView bac; @BindView() FrameLayout fl; @BindView() ImageView image; @Override protected void onCreate(Bundle savedInstanceState) { te(savedInstanceState); setContentView(ty_scrolling2); (this); (this); ha(0f); totalHeight = getResources().getDimension(_bar_height); toolBarHeight = getResources().getDimension(_bar_height); offSetHeight = totalHeight - toolBarHeight; /** * 移动效果值/最终效果值 = 移动距离/ 能移动总距离(确定) */ ffsetChangedListener(new etChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { //第⼀次进⼊获取⾼度,以及差值 ⾼度差⽐值 if (llHeight == 0){ llHeight = suredHeight(); params = (Params) outParams(); //算出⾼度偏移量⽐值 相对与llHeight llHeightOffScale = 1.0f - (toolBarHeight / llHeight); //得到滑动差值 就是布局marginTop llOffDistance = gin; //得到滑动⽐值 llOffDistanceScale = llOffDistance / offSetHeight; } //滑动⼀次 得到渐变缩放值 float alphaScale = (-verticalOffset) / offSetHeight; //获取⾼度缩放值 float llHeightScale = 1.0f-(llHeightOffScale*((-verticalOffset)/offSetHeight)); //计算maigintop值 float distance = llOffDistance - (-verticalOffset)*llOffDistanceScale; ha(1.0f-alphaScale); ha(alphaScale); = (int)(llHeight* llHeightScale); gins(0,(int)distance,0,0); tLayout(); } }); }}
发布者:admin,转转请注明出处:http://www.yc00.com/news/1689216920a222398.html
评论列表(0条)