仿QQ空间之打造个性化可拉伸头部控件
1、自定义控件
1、这里引用一个xml文件做为listview的headerView, LayoutInflater. inflate()的时候,注意最后的root为null,而不是this,以防 addHeaderView时出问题。2、监听overScrollBy(),下拉过度时,放大mImageView。
3、监听onScrollChanged(),mImageView被放大了,且正在往上推时,缩小mImageView。
4、有一种特殊情况要注意:当放大后的mImageView.height+listview.height=屏幕高度时,再往上推时,会触发上拉过度,而不会调用 onScrollChanged中的缩小方法,此时需要处理下。
5、监听onTouchEvent(),松手后,开始恢复默认状态的动画。
package com.luocen_qqzone_overlistview; import ndroid.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.animation.Animation; import android.view.animation.Transformation; import android.widget.ImageView; import android.widget.ListView; /** * Description: 仿QQ空间可拉伸头部特效 * Author: zsk * Date: 2018/2/2 14:18 * Email: [email protected] */ public class ParallaxListView extends ListView { private ImageView mImageView; private ImageView mHeaderImageView; private int mImageViewHeight=0; public ParallaxListView(Context context, AttributeSet attrs) { super(context, attrs); mImageViewHeight=context.getResources().getDimensionPixelSize(R.dimen.header_height); } //背景图片拉伸 public void setZoomImageView(ImageView iv){ mImageView=iv; } //头像旋转 public void setHeaderImageView(ImageView iv){ mHeaderImageView=iv; } /** * 过度滑动 * <p> * 注意:deltaX与deltaY与坐标系方向相反!!! * @param deltaX 水平增量(-右拉过度,+左拉过度) * @param deltaY 竖直增量(-下拉过度,+上拉过度) **/ @Override protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) { if(deltaY<0){ //下拉过度 对图片进行放大 mImageView.getLayoutParams().height=mImageView.getHeight()-deltaY; mImageView.requestLayout(); //头像的旋转 mHeaderImageView.setRotation(mHeaderImageView.getRotation()-deltaY); }else{//一种特殊情况:当放大后的mImageView.height+listview.height=屏幕高度时,再往上推时,会触发上拉过度,而不会调用onScrollChanged中的缩小方法 if(mImageView.getHeight()>mImageViewHeight) { mImageView.getLayoutParams().height = mImageView.getHeight() - deltaY; mImageView.requestLayout(); //头像的旋转 mHeaderImageView.setRotation(mHeaderImageView.getRotation()-deltaY); } } return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { //让ImageView上滑时缩小,监听 View header = (View) mImageView.getParent(); if(header.getTop()<0 && mImageView.getHeight()>mImageViewHeight){ //头像的旋转 mHeaderImageView.setRotation(mHeaderImageView.getRotation() + header.getTop()); mImageView.getLayoutParams().height=mImageView.getHeight()+header.getTop(); header.layout(header.getLeft(),0,header.getRight(),header.getHeight()); mImageView.requestLayout(); } super.onScrollChanged(l, t, oldl, oldt); } @Override public boolean onTouchEvent(MotionEvent ev) { //监听松开手 int action = ev.getAction(); if(action==MotionEvent.ACTION_UP){ ResetAnimation resetAnimation=new ResetAnimation(mImageViewHeight); resetAnimation.setDuration(300); mImageView.startAnimation(resetAnimation); } return super.onTouchEvent(ev); } public class ResetAnimation extends Animation{ private int delay ; //高度差 private int currentHeight ; //当前的高度 private int mHeaderRotation; // 起始值 private int mHeaderDestRotation=0; //终止值 public ResetAnimation(int targetHeight){ //targetHeight 最终恢复的高度 delay = mImageView.getHeight() - targetHeight; currentHeight = mImageView.getHeight(); mHeaderRotation= (int) mHeaderImageView.getRotation(); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { //interpolatedTime(0.0 to 1.0) 执行的百分比 //减小ImageView的高度 mImageView.getLayoutParams().height= (int) (currentHeight-delay*interpolatedTime); mImageView.requestLayout(); //头像的旋转 int rotation= (int) (mHeaderRotation+(mHeaderDestRotation-mHeaderRotation)*interpolatedTime); mHeaderImageView.setRotation(rotation); super.applyTransformation(interpolatedTime, t); } } }
2.控件的使用
package com.luocen_qqzone_overlistview; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.ArrayAdapter; import android.widget.ImageView; public class MainActivity extends AppCompatActivity { private ParallaxListView mListView; private ImageView iv; private ImageView iv_icon; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { View header=View.inflate(this,R.layout.header_view,null); mListView=findViewById(R.id.lv); iv=header.findViewById(R.id.iv_header); iv_icon=header.findViewById(R.id.iv_icon); ArrayAdapter<String> adapter=new ArrayAdapter(this,android.R.layout.simple_list_item_1, new String[]{ "星期一 去动脑学院上课", "星期二 去有心课堂上课", "星期三 去慕课网上课", "星期四 去极客学院上课", "星期五 去菜鸟教程上课", "星期六 去泡在网上的日子上课", "星期日 去Android开发中文站上课", }); mListView.addHeaderView(header); mListView.setZoomImageView(iv); mListView.setHeaderImageView(iv_icon); mListView.setAdapter(adapter); } }
3.依赖的资源:
R.layout.header_view:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/iv_header" android:layout_width="match_parent" android:layout_height="@dimen/header_height" android:scaleType="centerCrop" android:src="@mipmap/love"/> <ImageView android:id="@+id/iv_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@id/iv_header" android:layout_margin="10dp" android:scaleType="centerCrop" android:src="@mipmap/ic_launcher_round"/> </RelativeLayout>
R.layout.activity_main:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.luocen_qqzone_overlistview.ParallaxListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
项目源码地址:https://github.com/zhangshangkun/OverListView.git