Android_滑动的时候头部变化效果
废话少说,直接上图哦
先看看上面的布局。从上到下:头部使用相对布局,然后是三个选项。然后线性布局里面装的fragment,fragment里面又是能够上啦刷新的listview。我的思路是准备在activity里面直接实现。
activtiy里面有两个处理事件的方法
onTouchEvent(MotionEvent event)
dispatchTouchEvent(MotionEvent ev)
这两个事件选哪个合适呢?肯定是选第二个赛。选第一个的话肯定实现不起效果。由于事件传递(不懂百度),就被listview消耗了。
以下进入正题:
第一步:滚动的时候试着改变头部的高度
第二步:逐渐让周围不须要的字体消失
第三步:依据偏移率计算偏移量。然后把图片和须要的文字移动到顶端中心处
先声明须要用到的数据,以下所有列举出来
private int mLastY = 0; //最后的点 private static int mNeedDistance; // 须要滑动的距离 private static int mMinHight; //最小高度 private static int mOrignHight; //原始的高度 private int mCurrentDistance = 0; //当前的距离 private float mRate = 0; //距离与目标距离的变化率 mRate=mCurrentDistance/mNeedDistance private int mPhotoOriginHeight; //图片的原始高度 private int mPhotoOriginWidth; //图片的原始宽度 private int mPhotoLeft; //图片距左边的距离 private int mPhotoTop; //图片距离上边的距离 private int mPhotoNeedMoveDistanceX; // 图片须要移动的X距离 private int mPhotoNeedMoveDistanceY; // 图片须要移动的Y距离 //须要移动的文字 private int mTextLeft; //文字距左边的距离 private int mTextTop; //文字距离上边的距离 private int mTextNeedMoveDistanceX; // 文字须要移动的X距离 private int mTextNeedMoveDistanceY; //文字须要移动的Y距离 /** * 初始化须要滚动的距离 */ private void initDistance() { mOrignHight = rl_head.getLayoutParams().height; mMinHight = UIUtils.dip2px(this, 45); //设置最小的高度为这么多 mNeedDistance = mOrignHight - mMinHight; RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) img_head_portrait.getLayoutParams(); mPhotoOriginHeight = params.height; mPhotoOriginWidth = params.width; mPhotoLeft = params.leftMargin; mPhotoTop = params.topMargin; mPhotoNeedMoveDistanceX = UIUtils.getWindowWidth(this) / 2 - mPhotoLeft - mMinHight; mPhotoNeedMoveDistanceY = mPhotoTop - UIUtils.dip2px(this, 10); /*******************移动的文字初始化***************************/ RelativeLayout.LayoutParams textParams = (RelativeLayout.LayoutParams) tv_user_name.getLayoutParams(); mTextLeft = textParams.leftMargin; mTextTop = textParams.topMargin; mTextNeedMoveDistanceX = UIUtils.getWindowWidth(this) / 2 - mTextLeft + 10; mTextNeedMoveDistanceY = mTextTop - mMinHight / 2 / 2; //这里计算有点误差,正确的应该是剪去获取textview高度的一半 }
实现第一步操作:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = (int) ev.getY(); LogUtils.d(TAG, "ACTION_MOVE==mCurrentDistance" + mCurrentDistance); return super.dispatchTouchEvent(ev); //传递事件 比如能够用来子view的点击事件等 case MotionEvent.ACTION_MOVE: int y = (int) ev.getY(); int dy = mLastY - y; LogUtils.d(TAG, "ACTION_MOVE==mCurrentDistance" + mCurrentDistance); if (mCurrentDistance >= mNeedDistance && dy > 0) { return super.dispatchTouchEvent(ev); //传递事件 } if (mCurrentDistance <= 0 && dy < 0) { return super.dispatchTouchEvent(ev); //把事件传递进去 } //改变布局 changeTheLayout(dy); mLastY = y; break; case MotionEvent.ACTION_UP: checkTheHeight(); LogUtils.d(TAG, "ACTION_MOVE==mCurrentDistance" + mCurrentDistance); return super.dispatchTouchEvent(ev); } return false; }
改变布局的大小的:
/** * 通过滑动的偏移量 * * @param dy */ private void changeTheLayout(int dy) { final ViewGroup.LayoutParams layoutParams = rl_head.getLayoutParams(); layoutParams.height = layoutParams.height - dy; rl_head.setLayoutParams(layoutParams); checkTheHeight(); rl_head.requestLayout(); //计算当前移动了多少距离 mCurrentDistance = mOrignHight - rl_head.getLayoutParams().height; mRate = (float) (mCurrentDistance * 1.0 / mNeedDistance); changeTheAlphaAndPostion(mRate); //获取偏移率然后改变某些控件的透明度,和位置 LogUtils.d(TAG, "ACTION_MOVE==dy" + dy); }
获取了偏移率(0.0-1.0),然后就能够依据这个改变透明度了和大小了。
/** * 依据变化率来改变这些这些控件的变化率位置 * * @param rate */ private void changeTheAlphaAndPostion(float rate) { //先改变一些控件的透明度 if (rate >= 1) { tv_user_hosipital.setVisibility(View.GONE); tv_user_hosipital_level.setVisibility(View.GONE); tv_user_project.setVisibility(View.GONE); } else { tv_user_hosipital.setVisibility(View.VISIBLE); tv_user_hosipital_level.setVisibility(View.VISIBLE); tv_user_project.setVisibility(View.VISIBLE); tv_user_hosipital.setAlpha(1 - rate); tv_user_hosipital_level.setAlpha(1 - rate); tv_user_project.setAlpha(1 - rate); tv_user_hosipital.setScaleY(1 - rate); tv_user_hosipital.setScaleX(1 - rate); tv_user_hosipital_level.setScaleY(1 - rate); tv_user_hosipital_level.setScaleX(1 - rate); tv_user_project.setScaleY(1 - rate); tv_user_project.setScaleX(1 - rate); } //接下来是改变控件的大小和位置了 (这就是关键了) final RelativeLayout.LayoutParams photoParams = (RelativeLayout.LayoutParams) img_head_portrait.getLayoutParams(); photoParams.width = (int) (mPhotoOriginWidth - (rate * (mPhotoOriginWidth - mMinHight - UIUtils.dip2px(this, 10)))); photoParams.height = (int) (mPhotoOriginWidth - (rate * (mPhotoOriginWidth - mMinHight - UIUtils.dip2px(this, 10)))); photoParams.leftMargin = (int) (mPhotoLeft + mPhotoNeedMoveDistanceX * rate); photoParams.topMargin = (int) (mPhotoTop - mPhotoNeedMoveDistanceY * rate); LogUtils.d(TAG, "photoParams.leftMargin" + photoParams.leftMargin); LogUtils.d(TAG, " photoParams.topMargin" + photoParams.topMargin); img_head_portrait.setLayoutParams(photoParams); /*********************文字设置****************************/ final RelativeLayout.LayoutParams textParams = (RelativeLayout.LayoutParams) tv_user_name.getLayoutParams(); textParams.leftMargin = (int) (mTextLeft + mTextNeedMoveDistanceX * rate); textParams.topMargin = (int) (mTextTop - mTextNeedMoveDistanceY * rate); LogUtils.d(TAG, "textParams.leftMargin" + textParams.leftMargin); LogUtils.d(TAG, " textParams.topMargin" + textParams.topMargin); tv_user_name.setLayoutParams(textParams); }
卧槽,搞忘了一个方法,滑动的时候须要检查边界值;这里写了一个方法:
/** * 检查上边界和下边界 */ private void checkTheHeight() { final ViewGroup.LayoutParams layoutParams = rl_head.getLayoutParams(); if (layoutParams.height < mMinHight) { layoutParams.height = mMinHight; rl_head.setLayoutParams(layoutParams); rl_head.requestLayout(); } if (layoutParams.height > mOrignHight) { layoutParams.height = mOrignHight; rl_head.setLayoutParams(layoutParams); rl_head.requestLayout(); } }
另一个关键的地方,布局文件的时候 最好是图片控件和须要移动的文字textview不要依赖于其它控件,不然计算margin非常麻烦,所以我布局文件就用了简单粗糙的来实现布局:
须要变化的图片控件
<com.facebook.drawee.view.SimpleDraweeView android:id="@+id/img_head_portrait" android:layout_width="90dp" android:layout_height="90dp" android:layout_centerVertical="true" android:layout_marginLeft="@dimen/margin_20dp" android:padding="1dp" fresco:fadeDuration="500" fresco:placeholderImage="@mipmap/icon_user_avatar" />
须要变化的文字控件
<TextView android:id="@+id/tv_user_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="120dp" //这个距离直接设置的 ,不要用align。。。这个属性,不然不好计算margin android:layout_marginTop="@dimen/margin_30dp" //这个也是一样的道理 android:text="蒋心平" android:textColor="@color/white" android:textSize="@dimen/text_size_18" />
几乎相同就这样就能实现上面的效果了。当做完这个功能的时候,我突然认为一些主流app。实现的向上滑动,title慢慢消失或者隐藏就so easy了,原理都是一样的。
仅仅要对事件分发拦截机制有一点认识都能实现这种效果了。