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

这里写图片描述
(使用格式工厂将视频转换成gif格式时影响了gif效果,运行在真机上不影响效果)

这个效果是采用ListView并给ListView添加一个头部来实现的,当然了要处理ListView的上拉,下拉及松开肯定要对ListView自定义;

先来看下ListView的头部xml文件:

<?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/layout_header_image"
        android:layout_width="match_parent"
        android:layout_height="@dimen/size_default_height"
        android:scaleType="centerCrop"
        android:src="@drawable/image_header4"/>
    <ImageView
        android:id="@+id/header_iamge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/header"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="40dp"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="40dp"/>

</RelativeLayout>

很简单就是两个ImageView,不过需要设置背景ImageView的scaleType属性值为centerCrop(均衡的缩放图像(保持图像原始比例),使图片的两个坐标(宽、高)都大于等于 相应的视图坐标(负的内边距),图像则位于视图的中央),这样头部背景在ListView下拉、上拉及手势松开是能进行均衡的缩放效果;

接着动作就是自定义ListView:

public class ParallaxListView extends ListView {
    private ImageView mImageView;
    private ImageView headerImageView;
    private int mImageViewHeight = 0;

    public ParallaxListView(Context context) {
        this(context, null);
    }

    public ParallaxListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ParallaxListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mImageViewHeight = context.getResources().getDimensionPixelSize(R.dimen.size_default_height);
    }

    public void setZoomImageView(ImageView iv) {
        this.mImageView = iv;
    }
    public void setHeaderImageView(ImageView iv){
        this.headerImageView=iv;
    }
    @Override
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
        /**
         * 监听ListView(ScrollView)的滑动过度
         * dx,dy增量deltaY
         * -:下拉过度
         * +:上拉过度
         */
        if (deltaY < 0) {
            //放大 对ImageView的高度重新赋值
            mImageView.getLayoutParams().height = mImageView.getHeight() - deltaY;
            mImageView.requestLayout();
            //旋转
//            headerImageView.setRotation(headerImageView.getRotation()-deltaY);
        } else {
            //缩小对ImageView的高度重新赋值
            if (mImageView.getHeight() > mImageViewHeight) {
                mImageView.getLayoutParams().height = mImageView.getHeight() - deltaY;
                mImageView.requestLayout();
            }
        }
        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();
        //header.getTop() 头部滑出去的距离
        if (header.getTop() < 0 && mImageView.getHeight() > mImageViewHeight) {
            mImageView.getLayoutParams().height = mImageView.getHeight() + header.getTop();
            header.layout(header.getLeft(), 0, header.getRight(), header.getBottom());
            mImageView.requestLayout();
        }
        super.onScrollChanged(l, t, oldl, oldt);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        //监听松开手 弹回原来的状态
        int action = ev.getAction();
        if(action==MotionEvent.ACTION_UP){
            //给ImagView设置动画效果
            ResetAnimation animation=new ResetAnimation(mImageView,mImageViewHeight);
            animation.setDuration(300);
            mImageView.startAnimation(animation);
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 自定义动画
     */
    public class ResetAnimation extends Animation{
        private ImageView iv;
        private int targetHeight;
        private int originalHeight;
        private int extraHeight;
        public ResetAnimation(ImageView iv,int targetHeight){
            this.iv=iv;
            //最终恢复的高度
            this.targetHeight=targetHeight;
            //现在的高度
            this.originalHeight=iv.getHeight();
            this.extraHeight=originalHeight-targetHeight;
        }
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            //interpolatedTime (0.0 to 1.0)执行的百分比
            iv.getLayoutParams().height = (int) (originalHeight-extraHeight*interpolatedTime);
            iv.requestLayout();
            super.applyTransformation(interpolatedTime, t);
        }
    }
}

在ParallaxListView里面需要重写三个方法:

overScrollBy();-->ListView、ScrollView等上拉或下拉滑动过度时回调;
onScrollChanged;-->ListView、ScrollView等滑动时回调;
onTouchEvent();-->ListView、ScrollView等手势触摸或松开时回调;

activity及xml布局文件中引用和使用:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.qqheader.MainActivity">

    <com.qqheader.ParallaxListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>
public class MainActivity extends AppCompatActivity {
    private ParallaxListView listview;
    private List<String> list = new ArrayList<>();
    private ListAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getData();
        listview = (ParallaxListView) findViewById(R.id.listview);
        View headerView=View.inflate(this,R.layout.listview_header,null);
        ImageView iv = (ImageView) headerView.findViewById(R.id.layout_header_image);
        ImageView headerIamge= (ImageView) headerView.findViewById(R.id.header_iamge);
        adapter = new ListAdapter(this, list);
        listview.addHeaderView(headerView);
        listview.setAdapter(adapter);

        listview.setZoomImageView(iv);
        listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(MainActivity.this,list.get(position-1),Toast.LENGTH_LONG).show();
            }
        });
    }

    private void getData() {
        list.add("星期一");
        list.add("星期二");
        list.add("星期三");
        list.add("星期四");
        list.add("星期五");
        list.add("星期六");
        list.add("星期日");
        list.add("星期一");
        list.add("星期二");
        list.add("星期三");
        list.add("星期四");
        list.add("星期五");
        list.add("星期六");
        list.add("星期日");
    }
}

源码地址:
https://pan.baidu.com/s/1dFKuKhV

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值