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

最近有研究了QQ空间可拉伸头部控件的listView。如何去做呢?这里使用了自定义listView的方法。先看效果图吧:

究竟如何去做呢?
可以用的方法有:
* 1.继承 extends ViewGrop
* 2.RecycleView +Behavior+CoordinateLayout
* 3.ViewGroup 组合控件
* 4.ListView + headView

这次我们主要用原生的自定义listView去做。
- 1.extends 继承 ListView
- 2.监听过度监听,在缩放头部图片重写overScrollBy方法
- 重写onScrollChanged方法监听度放大时,执行缩小图片
- 重写onTouchEvent方法,执行触摸时释放事件的处理

/**
 * 类功能描述:</br>
 *  仿QQ空间之打造个性化可拉伸头部控件</br>
 * @author yuyahao
 * @version 1.0 </p> 修改时间:</br> 修改备注:</br>
 */

public class CustomerScrollZoomListView extends ListView{
    private ImageView imageView;
    private int mMeasureWeight;
    public CustomerScrollZoomListView(Context context, AttributeSet attrs) {
        super(context, attrs);
         mMeasureWeight = context.getResources().getDimensionPixelSize(R.dimen.dp200);
    }
    public CustomerScrollZoomListView(Context context) {
        super(context);
    }
    public void setZoomImageView(ImageView iView ){
         imageView = iView;

    }

    @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){//下拉过度  对图片进行放大
            imageView.getLayoutParams().height = imageView.getHeight() - deltaY;
            imageView.requestLayout();
        }else{//上拉过度时
            imageView.getLayoutParams().height = imageView.getHeight() - deltaY;
            imageView.requestLayout();
        }
        LogUtil.i("yuyahao","deltaY:  "+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 view = (View) imageView.getParent();
        int detalY = view.getTop();//此时 detay 为负值
       if(imageView.getHeight() > mMeasureWeight){//如果当前图片的高度 > 初始高度
            imageView.getLayoutParams().height = imageView.getHeight() + detalY;
            imageView.requestLayout();
        }
        LogUtil.i("yuyahao","----   deltaY:  "+detalY);
        super.onScrollChanged(l, t, oldl, oldt);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_UP://松手释放时
                MyCustomserAnimation myCustomserAnimation = new MyCustomserAnimation(mMeasureWeight);
                myCustomserAnimation.setDuration(300);
                myCustomserAnimation.setInterpolator(new BounceInterpolator());
                imageView.startAnimation(myCustomserAnimation);
                break;
        }
        return super.onTouchEvent(ev);
    }
    public class MyCustomserAnimation extends Animation{
        private int delay ;//高度差
        private int currentHeight ; //当前的高度
        public MyCustomserAnimation( int targetHeight){
            //this.delay = delay;
            delay = imageView.getHeight()  - targetHeight;
            currentHeight =  imageView.getHeight();
        }
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            imageView.getLayoutParams().height = (int) (currentHeight  - delay * interpolatedTime);
            imageView.requestLayout();
            super.applyTransformation(interpolatedTime, t);
        }
    }
}

这里重写了overScrollBy方法
这里源码是怎么说的呢?

  /**
     * This is called in response to an internal scroll in this view (i.e., the
     * view scrolled its own contents). This is typically as a result of
     * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been
     * called.
     *
     * @param l Current horizontal scroll origin.
     * @param t Current vertical scroll origin.
     * @param oldl Previous horizontal scroll origin.
     * @param oldt Previous vertical scroll origin.
     */
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        notifySubtreeAccessibilityStateChangedIfNeeded();

        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
            postSendViewScrolledAccessibilityEventCallback();
        }

        mBackgroundSizeChanged = true;
        if (mForegroundInfo != null) {
            mForegroundInfo.mBoundsChanged = true;
        }

        final AttachInfo ai = mAttachInfo;
        if (ai != null) {
            ai.mViewScrollChanged = true;
        }

        if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) {
            mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt);
        }
    }

大致意思我们都可以看得出来.大致意思是响应于该视图中的内部滚动而调用的(即视图滚动其自己的内容)比如:eltaY < 0的时候下拉过度 对图片进行放大。 小于0时,上拉过度。

日前google上搜索“android overscroll”,对此效果的介绍很多,但关于其具体使用方式和实现,则很少涉及,偶有提及,也经常答非所问或似是而非,反而误导了别人。于是我查阅了android相关源码,并做了一些测试,在此讲讲我的理解。

首先是overscroll功能本身。
- 在最顶层的View类提供了支持,可通过setOverScrollMode函数控制其出现条件。但其实View中并没有实现overscroll功能,
- 提供了一个辅助函数overScrollBy,该函数根据overScrollMode和内容是否需要滚动控制最大滚动范围。
- 最后将计算结果传给onOverScrolled实现具体的overscroll功能
- 但此函数在View类中是全空的
overscroll功能真正的实现分别在ScrollView、AbsListView、HorizontalScrollView和WebView中各有一份,代码基本一样。
- 以ScrollView为例,它在处理笔点移动消息时调用overScrollBy来滚动视图,然后重载了overScrollBy函数来实现具体功能,其位置计算通过OverScroller类实现。
- OverScroller作为一个计算引擎,应该是一个独立的模块,具体滚动效果和范围都不可能通过它来设置,我觉得没有必要细看。但滚动位置最终是它给出的,那相关数据肯定要传递给它。
- 回头看overScrollBy函数,它有两个控制overScroll出界范围的参数,几个实现里面都是取自ViewConfiguration.getScaledOverscrollDistance,而这个参数的值在我的源码中都是0,而且我没找到任何可以影响其结果的设置。

Activity中的代码:

/**
 * 类功能描述:</br>
 *  仿QQ空间之打造个性化可拉伸头部控件</br>
 * @author yuyahao
 * @version 1.0 </p> 修改时间:</br> 修改备注:</br>
 */
public class CustomerScrollZoomListViewActivity extends BaseActivity{
    @Bind(R.id.lv_customser_zoomscroll)
    CustomerScrollZoomListView lv_customser_zoomscroll;
    private List<Student> list = new ArrayList<>();
    private ZoomScrollListViewAdapter zoomScrollListViewAdapter;
    private View headView;
    @Override
    protected void initData() {
        setContentView(R.layout.activity_customerscrollzoomlistview);
        ButterKnife.bind(this);
        list.addAll(ServiceData.getStudentList());

        zoomScrollListViewAdapter = new ZoomScrollListViewAdapter(CustomerScrollZoomListViewActivity.this,list,R.layout.item_xzoomscrollview);
        headView = LayoutInflater.from(CustomerScrollZoomListViewActivity.this).inflate(R.layout.zoom_headview,null);
        ImageView iamgeView = (ImageView) headView.findViewById(R.id.iv_zoom_head);
        lv_customser_zoomscroll.setZoomImageView(iamgeView);
        lv_customser_zoomscroll.addHeaderView(headView);
        lv_customser_zoomscroll.setAdapter(zoomScrollListViewAdapter);

    }

}

xml布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.yolo.myapplication.activity.view.CustomerScrollZoomListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/lv_customser_zoomscroll"
        />
</LinearLayout>

adapter适配器

public class ZoomScrollListViewAdapter extends CommonAdapter<Student> {
    private Context context;

    public ZoomScrollListViewAdapter(Context context, List<Student> listDatas, int layoutId) {
        super(context, listDatas, layoutId);
        this.context = context;
    }

    @Override
    protected void fillData(ViewHolder holder, int position) {
        TextView actNum = holder.getView(R.id.team_item_active_num);
        TextView time = holder.getView(R.id.team_item_time);
        TextView title = holder.getView(R.id.team_item_title);
        ImageView icon = holder.getView(R.id.team_item_icon);
        Student item = listDatas.get(position);
        actNum.setText(String.valueOf(item.getList().size()) + "");
        time.setText(String.valueOf(item.getList().get(0).getPerListenceName()) + "");
        title.setText(item.getName());
    }
}

adapter适配器请参考:
教你打造一个万能的适配器
item:布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:gravity="center_vertical"
    android:layout_height="match_parent">
    <ImageView
        android:layout_width="@dimen/dp80"
        android:layout_height="@dimen/dp80"
        android:background="@drawable/img2"
        android:scaleType="fitXY"
        android:id="@+id/team_item_icon"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_marginLeft="@dimen/dp10"
        android:orientation="vertical"
        android:layout_height="@dimen/dp80">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/team_item_title"
            android:gravity="center_vertical"
            android:layout_weight="1"
            android:text="卡卡罗特"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:layout_height="match_parent"
            android:gravity="center_vertical">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="天不排名"
                android:id="@+id/team_item_time"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/dp20"
                android:text="战斗值: "

                android:id="@+id/team_item_active_num"/>

        </LinearLayout>
    </LinearLayout>
</LinearLayout>

项目源码地址:MyZoomListView.rar

如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809
微信公众号:终端研发部

专攻技术

(欢迎关注学习和交流)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

androidstarjack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值