Android中如何使用CoordinatorLayout+AppBarLayout实现拉伸顶部图片功能
创始人
2024-12-23 05:40:26
0次

直接上布局文件代码

                                                                                    

上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 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

重点在于设置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);   }  } }}

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...