详解Android使用CoordinatorLayout+AppBarLayout实现拉伸顶部图片功能
程序员文章站
2023-11-18 19:13:58
一、国际惯例,先看下效果图
二、不跟你多bb直接上布局文件代码
...
一、国际惯例,先看下效果图
二、不跟你多bb直接上布局文件代码
<?xml version="1.0" encoding="utf-8"?> <linearlayout 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" tools:context=".mainactivity" android:clipchildren="false" android:cliptopadding="false"> <androidx.coordinatorlayout.widget.coordinatorlayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.appbar.appbarlayout android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_behavior="com.ce.myscrollimg.appbarlayoutoverscrollviewbehavior"> <com.google.android.material.appbar.collapsingtoolbarlayout android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_scrollflags="scroll" android:clipchildren="false" android:cliptopadding="false"> <com.ce.myscrollimg.disinterceptnestedscrollview android:layout_width="match_parent" android:layout_height="wrap_content" android:clipchildren="false" android:cliptopadding="false" app:layout_collapsemode="parallax" app:layout_collapseparallaxmultiplier="0.8"> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <imageview android:id="@+id/iv_bg" android:layout_width="match_parent" android:layout_height="130dp" android:src="@mipmap/ic_cover_1" android:scaletype="centercrop"/> </linearlayout> </com.ce.myscrollimg.disinterceptnestedscrollview> <com.ce.myscrollimg.disinterceptnestedscrollview android:layout_width="match_parent" android:layout_height="wrap_content" android:tag="middle" android:layout_margintop="130dp"> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <view android:layout_width="match_parent" android:layout_height="80dp" android:background="#fff003"/> <view android:layout_width="match_parent" android:layout_height="80dp" android:background="#ff3300"/> </linearlayout> </com.ce.myscrollimg.disinterceptnestedscrollview> <androidx.appcompat.widget.toolbar android:layout_width="match_parent" android:layout_height="wrap_content" android:tag="toolbar" app:layout_collapsemode="pin"> </androidx.appcompat.widget.toolbar> </com.google.android.material.appbar.collapsingtoolbarlayout> </com.google.android.material.appbar.appbarlayout> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <com.google.android.material.tabs.tablayout android:id="@+id/toolbar_tab" android:layout_width="match_parent" android:layout_height="40dp" android:layout_gravity="center" app:tabindicatorcolor="#ffc000" app:tabindicatorfullwidth="false" app:tabindicatorheight="0dp" app:tabmode="scrollable" android:layout_margintop="4dp" android:layout_marginbottom="2dp" app:tabselectedtextcolor="#ffc000" app:tabtextcolor="#ffffff" app:tabmaxwidth="90dp" app:tabpaddingend="-1dp" /> <com.ce.myscrollimg.noscrollviewpager android:id="@+id/vp_content" android:layout_width="match_parent" android:layout_height="match_parent" /> </linearlayout> </androidx.coordinatorlayout.widget.coordinatorlayout> </linearlayout>
三、上java代码
package com.ce.myscrollimg; import androidx.appcompat.app.appcompatactivity; import androidx.fragment.app.fragment; import androidx.viewpager.widget.viewpager; import android.graphics.typeface; import android.os.bundle; import android.util.typedvalue; import android.view.layoutinflater; import android.view.view; import android.view.viewgroup; import android.widget.linearlayout; import android.widget.textview; import com.google.android.material.tabs.tablayout; import java.util.arraylist; import java.util.list; public class mainactivity extends appcompatactivity { private tablayout toolbar_tab; private noscrollviewpager vp_content; private viewpageradapter vpadapter; private list<fragment> listfragment = new arraylist<>(); @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); initview(); } //初始化view private void initview(){ //tab toolbar_tab = findviewbyid(r.id.toolbar_tab); // vp_content = findviewbyid(r.id.vp_content); vpadapter = new viewpageradapter(getsupportfragmentmanager(),listfragment); vp_content.setadapter(vpadapter); vp_content.setoffscreenpagelimit(2); toolbar_tab.setupwithviewpager(vp_content); for(int i=0;i<12;i++){ listfragment.add(ceshifragment.newinstance("第"+i+"页")); } vpadapter.notifydatasetchanged(); for(int i=0;i<listfragment.size();i++){ tablayout.tab tab = toolbar_tab.gettabat(i); view customview = layoutinflater.from(this).inflate(r.layout.tab_text, null, false); textview textview = customview.findviewbyid(r.id.tv_custom_tab); // linearlayout.layoutparams layoutparams = new linearlayout.layoutparams(viewgroup.layoutparams.wrap_content, viewgroup.layoutparams.wrap_content); // layoutparams.weight = 0; // textview.setlayoutparams(layoutparams); if (i == 0) { textview.settext("推荐"); } else { textview.settext("第"+i+"页"); } if (i == 0) { textview.settextsize(typedvalue.complex_unit_sp, 16); textview.settypeface(typeface.defaultfromstyle(typeface.bold)); textview.settextcolor(getresources().getcolor(r.color.color_ffffc000)); } else { textview.settextsize(typedvalue.complex_unit_sp, 14); textview.settextcolor(getresources().getcolor(r.color._1e1e1e)); } tab.setcustomview(customview); } toolbar_tab.addontabselectedlistener(new tablayout.ontabselectedlistener() { @override public void ontabselected(tablayout.tab tab) { view view = tab.getcustomview(); if (view != null) { textview textview = view.findviewbyid(r.id.tv_custom_tab); textview.settextsize(typedvalue.complex_unit_sp, 16); textview.settypeface(typeface.defaultfromstyle(typeface.bold)); textview.settextcolor(getresources().getcolor(r.color.color_ffffc000)); } vp_content.setcurrentitem(tab.getposition()); } @override public void ontabunselected(tablayout.tab tab) { view view = tab.getcustomview(); if (view != null) { textview textview = view.findviewbyid(r.id.tv_custom_tab); if (textview != null) { textview.settextsize(typedvalue.complex_unit_sp, 14); textview.settypeface(typeface.defaultfromstyle(typeface.normal)); textview.settextcolor(getresources().getcolor(r.color._1e1e1e)); } } } @override public void ontabreselected(tablayout.tab tab) { } }); } }
四、重点在于设置appbarlayout的behavior这里自定义appbarlayoutoverscrollviewbehavior,下面贴出代码
package com.ce.myscrollimg; import android.animation.animator; import android.animation.valueanimator; import android.content.context; import android.util.attributeset; import android.view.view; import android.view.viewgroup; import androidx.appcompat.widget.toolbar; import androidx.coordinatorlayout.widget.coordinatorlayout; import androidx.core.view.viewcompat; import com.google.android.material.appbar.appbarlayout; /** * created by gjm on 2017/5/24. * 目前包括的事件: * 图片放大回弹 * 个人信息布局的top和botoom跟随图片位移 * toolbar背景变色 */ public class appbarlayoutoverscrollviewbehavior extends appbarlayout.behavior { private static final string tag = "overscroll"; private static final string tag_toolbar = "toolbar"; private static final string tag_middle = "middle"; private static final float target_height = 1500; private view mtargetview; private int mparentheight; private int mtargetviewheight; private float mtotaldy; private float mlastscale; private int mlastbottom; private boolean isanimate; private toolbar mtoolbar; private viewgroup middlelayout;//个人信息布局 private int mmiddleheight; private boolean isrecovering = false;//是否正在自动回弹中 private final float max_refresh_limit = 0.3f;//达到这个下拉临界值就开始刷新动画 public appbarlayoutoverscrollviewbehavior() { } public appbarlayoutoverscrollviewbehavior(context context, attributeset attrs) { super(context, attrs); } @override public boolean onlayoutchild(coordinatorlayout parent, appbarlayout abl, int layoutdirection) { boolean handled = super.onlayoutchild(parent, abl, layoutdirection); if (mtoolbar == null) { mtoolbar = parent.findviewwithtag(tag_toolbar); } if (middlelayout == null) { middlelayout = (viewgroup) parent.findviewwithtag(tag_middle); } // 需要在调用过super.onlayoutchild()方法之后获取 if (mtargetview == null) { mtargetview = parent.findviewbyid(r.id.iv_bg); if (mtargetview != null) { initial(abl); } } abl.addonoffsetchangedlistener(new appbarlayout.onoffsetchangedlistener() { @override public final void onoffsetchanged(appbarlayout appbarlayout, int i) { mtoolbar.setalpha(float.valueof(math.abs(i)) / float.valueof(appbarlayout.gettotalscrollrange())); } }); return handled; } @override public boolean onstartnestedscroll(coordinatorlayout parent, appbarlayout child, view directtargetchild, view target, int nestedscrollaxes, int x) { isanimate = true; if (target instanceof disinterceptnestedscrollview) return true;//这个布局就是middlelayout return super.onstartnestedscroll(parent, child, directtargetchild, target, nestedscrollaxes,x); } @override public void onnestedprescroll(coordinatorlayout coordinatorlayout, appbarlayout child, view target, int dx, int dy, int[] consumed, int x) { if (!isrecovering) { if (mtargetview != null && ((dy < 0 && child.getbottom() >= mparentheight) || (dy > 0 && child.getbottom() > mparentheight))) { scale(child, target, dy); return; } } super.onnestedprescroll(coordinatorlayout, child, target, dx, dy, consumed,x); } @override public boolean onnestedprefling(coordinatorlayout coordinatorlayout, appbarlayout child, view target, float velocityx, float velocityy) { if (velocityy > 100) {//当y速度>100,就秒弹回 isanimate = false; } return super.onnestedprefling(coordinatorlayout, child, target, velocityx, velocityy); } @override public void onstopnestedscroll(coordinatorlayout coordinatorlayout, appbarlayout abl, view target, int x) { recovery(abl); super.onstopnestedscroll(coordinatorlayout, abl, target,x); } private void initial(appbarlayout abl) { abl.setclipchildren(false); mparentheight = abl.getheight(); mtargetviewheight = mtargetview.getheight(); mmiddleheight = middlelayout.getheight(); } 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); middlelayout.settop(mlastbottom - mmiddleheight); middlelayout.setbottom(mlastbottom); if (onprogresschangelistener != null) { float progress = math.min((mlastscale - 1) / max_refresh_limit, 1);//计算0~1的进度 onprogresschangelistener.onprogresschange(progress, false); } } public interface onprogresschangelistener { /** * 范围 0~1 * * @param progress * @param isrelease 是否是释放状态 */ void onprogresschange(float progress, boolean isrelease); } public void setonprogresschangelistener(appbarlayoutoverscrollviewbehavior.onprogresschangelistener onprogresschangelistener) { this.onprogresschangelistener = onprogresschangelistener; } onprogresschangelistener onprogresschangelistener; private void recovery(final appbarlayout abl) { if (isrecovering) return; if (mtotaldy > 0) { isrecovering = true; 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())); middlelayout.settop((int) (mlastbottom - (mlastbottom - mparentheight) * animation.getanimatedfraction() - mmiddleheight)); if (onprogresschangelistener != null) { float progress = math.min((value - 1) / max_refresh_limit, 1);//计算0~1的进度 onprogresschangelistener.onprogresschange(progress, true); } } } ); anim.addlistener(new animator.animatorlistener() { @override public void onanimationstart(animator animation) { } @override public void onanimationend(animator animation) { isrecovering = false; } @override public void onanimationcancel(animator animation) { } @override public void onanimationrepeat(animator animation) { } }); anim.start(); } else { viewcompat.setscalex(mtargetview, 1f); viewcompat.setscaley(mtargetview, 1f); abl.setbottom(mparentheight); middlelayout.settop(mparentheight - mmiddleheight); // middlelayout.setbottom(mparentheight); isrecovering = false; if (onprogresschangelistener != null) onprogresschangelistener.onprogresschange(0, true); } } } }
五、源码下载
http://xiazai.jb51.net/201910/yuanma/myscrollimg_jb51.rar
总结
以上所述是小编给大家介绍的android使用coordinatorlayout+appbarlayout实现拉伸顶部图片功能,希望对大家有所帮助
下一篇: 【Nginx】实现负载均衡的几种方式
推荐阅读
-
详解Android使用CoordinatorLayout+AppBarLayout实现拉伸顶部图片功能
-
使用Java代码在Android中实现图片裁剪功能
-
Android编程使用加速度传感器实现摇一摇功能及优化的方法详解
-
Android使用ViewFlipper实现图片切换功能
-
使用Java代码在Android中实现图片裁剪功能
-
详解Android使用CoordinatorLayout+AppBarLayout实现拉伸顶部图片功能
-
Android 图片裁剪功能实现详解(类似QQ自定义头像裁剪)
-
Android使用ViewFlipper实现图片切换功能
-
使用javascript实现图片库的基本功能案例详解(附代码)
-
使用input标签和jquery实现多图片的上传和回显功能步骤详解