仿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地址
https://github.com/Huazhiling/DivQQZone