仿QQ空间打造可拉伸头部组件
本章没有什么难点和技术点,主要是大晚上的没啥事写着玩 -.-
首先先上一个效果图
全代码文件不超过150行 所以说超简单~ ~(当然前提是布局简单 只写了一个类似的效果而已)
进入正题
下面是布局文件得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.example.administrator.qqzone.MainActivity">
<com.example.administrator.qqzone.MyPullList
android:id="@+id/main_list"
android:layout_width="match_parent"
android:layout_height="match_parent"></com.example.administrator.qqzone.MyPullList>
</RelativeLayout>
这里的MyPullList是自定义的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"
android:orientation="vertical">
<ImageView
android:id="@+id/head_img"
android:layout_width="match_parent"
android:layout_height="@dimen/head_img_defualt_size_dp"
android:scaleType="centerCrop"
android:src="@mipmap/dog" />
<ImageView
android:id="@+id/head_leftimg"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_marginBottom="30dp"
android:layout_marginLeft="30dp"
android:scaleType="centerCrop"
android:src="@mipmap/tz" />
</RelativeLayout>
布局文件已经写完 在适配数据源之前我们先把这个自定义ListView写出来
public class MyPullList extends ListView {
public MyPullList(Context context, AttributeSet attrs) {
super(context, attrs, 0);
mImageViewHeigth = context.getResources().getDimensionPixelOffset(R.dimen.head_img_defualt_size_dp);
}
适配数据源不在做过多解释 贴代码看就行
public class MainActivity extends AppCompatActivity {
private MyPullList mainlist;
private View headView;
private ImageView iv;
private ImageView leftIv;
private List<String> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.mainlist = (MyPullList) findViewById(R.id.main_list);
headView = View.inflate(this, R.layout.listview_head, null);
iv = (ImageView) headView.findViewById(R.id.head_img);
leftIv = (ImageView) headView.findViewById(R.id.head_leftimg);
//消除阴影
mainlist.setOverScrollMode(View.OVER_SCROLL_NEVER);
initData();
mainlist.setImageBig(iv);
}
private void initData() {
list = new ArrayList<>();
for (int i = 0; i < 26; i++) {
list.add("嗯哼嗯哼蹦擦擦~" + (i + 1));
}
initAdapter();
}
private void initAdapter() {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
mainlist.addHeaderView(headView);
mainlist.setAdapter(adapter);
}
}
14行的head是我们要添加的头部 接下来的效果也只要是针对头部的
我们在initAdapter()方法中将头部添加进去 然后setAdapter
接下来主要在自定义的listView中做操作
首先我们需要重写overScrollBy方法监听滑动的事件
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
//这里的deltaY代表的是Y偏移量
if (deltaY < 0) {
//这里将图片的高度变大 为什么deltaY要除2呢? 是因为防止用户从头拉到底部 图片高度过大不好看
mIv.getLayoutParams().height = mIv.getHeight() - deltaY / 2;
mIv.requestLayout();
} else {
//这里的代码是当你上滑的时候缩放图片的
if (mIv.getHeight() > mImageViewHeigth) {
mIv.getLayoutParams().height = mIv.getHeight() + deltaY / 2;
mIv.requestLayout();
}
}
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
接着要重写onScrollChanged方法
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
//让Imageview上滑时放大监听
View head = (View) mIv.getParent();
//拿到父容器与顶部的高度
if (head.getTop() < 0 && mIv.getHeight() > mImageViewHeigth) {
mIv.getLayoutParams().height = mIv.getHeight() + head.getTop();
head.layout(head.getLeft(), 0, head.getRight(), head.getHeight());
mIv.requestLayout();
}
super.onScrollChanged(l, t, oldl, oldt);
}
主要的作用与父容器与顶部的距离 这里有一个mImageViewHeigth的变量是什么意思呢? 他代表的是图片的初始高度 我定义在了成员变量内
最后需要重写的是onTouchEvent方法
@Override
public boolean onTouchEvent(MotionEvent ev) {
//注意 这里只监听了ACTION_UP方法 是因为只有当用户抬起手指的时候才会让顶部回弹
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
//自定义了一个动画 下面直接贴代码
ResetAnimation animation = new ResetAnimation(mIv, mImageViewHeigth);
animation.setDuration(300);
mIv.startAnimation(animation);
break;
}
return super.onTouchEvent(ev);
}
动画代码————>
class ResetAnimation extends Animation {
private ImageView iv;
private int targetHeigth; //最终恢复的高度
private final int height;
private final int endHeigth;
//这个iv的参数也许用不到 可加可不加
public ResetAnimation(ImageView iv, int targetHeigth) {
this.iv = iv;
this.targetHeigth = targetHeigth;
this.height = mIv.getHeight();
this.endHeigth = height - targetHeigth;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
//不断调用 这个的代码比较关键 当手指抬起回调动画方法的时候这个方法是会被一直调用的
mIv.getLayoutParams().height = (int) (height - endHeigth * interpolatedTime);
mIv.requestLayout();
super.applyTransformation(interpolatedTime, t);
}
基本代码就只有这一些
github地址