仿QQ空间之打造个性化可拉伸头部控件

仿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