ListView实现类似WheelView效果的探究

不得不说,作为一名安卓码农,总是会有蛋蛋的忧伤,因为CP常说的就是:你看,人家ios的那个效果好炫酷,比如下面这样的

这里写图片描述

代码已上Github,部分代码有所调整,以Github上代码为准

需要Demo和源码的请戳这里…

作为一名合格的码农,实在不能忍,最后还是实现了这个效果,虽然没有ios的厉害。。。

实现的思路还是不复杂的,主要分两个方向:WheelView类似的思想(github一大堆)、ClipToPadding和ClipChildren取巧。因为我是用的取巧,所以我们下面只谈第二种方法。

难点有两个,一是精确地控制listview的item滚动到悬浮框内。因为大多数时候都不会是某个item刚好在悬浮框内的,但是唯一要考虑的情况也只有一种,即悬浮框内同时出现2个或多个item(设计需要,item的高度都是大于等于悬浮框的高度的,所以悬浮框内最多同时出现2个item,小于悬浮框的高度就会出现问题),取出最适合停留的item(这是个相对概念,大家可以修改代码扩展),我目前需要的就是item中间位置的y值和悬浮视图中间位置的y值最接近的一项,后面的代码里大家会看到如何处理的;

二是当listview只有很少的项时,怎么让listview可以滚动呢?这就需要ClipToPadding和ClipChildren来帮忙了。不知道这两个属性的童鞋可以上网查一查,我相信你会受益良多。ClipToPadding=false,我对这个属性简单理解就是,当你为listview设置了padingTop、padingBottom属性,listview会有pading的效果,但是当你滑动listview到顶部或底部时,listview的顶部或底部却不会出现pading的那部分区域,即listview的内容不再被pading的区域遮盖。ClipChildren=false,就是子视图可以超出父视图区域进行绘制。有了这两个属性,就可以解决listview item比较少时不能滚动的问题了。

由于设计需要滚动时item视图的放大和缩小,所以把处理放到了onscrolllistener的onscroll方法里,最后处理listview精确滚动的代码则要放到onscrolllistener的onScrollStateChanged方法里,这些都是可以修改的。

因为要实现这个效果需要adapter配合,所以代码也比较乱,但是注释还是比较详细的,大家慢慢看。

先看看WheelListView

package com.ykbjson.demo.customview.listview;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;

import com.ykbjson.demo.tools.SLog;

/**
 * 包名:com.ykbjson.demo.customview.listview
 * 描述:类似WheelView的ListView
 * 创建者:yankebin
 * 日期:2016/6/1
 */
public class WheelListView extends ListView {
   
    private static final int MAX_Y_OVERSCROLL_DISTANCE = 200;
    private final Object SCROLL_LOCK = new Object();
    //坐标都是相对于手机屏幕
    private int topY;//悬浮框顶部坐标
    private int middleY;//悬浮框中间坐标
    private int bottomY;//悬浮框底部坐标
    private int selectPosition;//滚动时adapter当前选中的position
    private boolean fromTouch;//当调用smoothScrollToPositionFromTop()方法时也会触发onScroll,需要屏蔽掉
    private WheelAdapter wheelAdapter;//数据适配器
    private OnSelectCallback callback;//滚动时的回调接口
    private int mMaxYOverScrollDistance;

    public interface OnSelectCallback {
   
        void onHandleScroll(int selectPosition);

        void onHandleIdle(WheelListView wheelListView, int selectPosition);
    }

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

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

    public WheelListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
//        initBounceListView();
        setClipChildren(false);
        setClipToPadding(false);
    }

    /**
     * 阻尼效果实现
     */
//    private void initBounceListView(){
   
//        //get the density of the screen and do some maths with it on the max overscroll distance
//        //variable so that you get similar behaviors no matter what the screen size
//        final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
//        final float density = metrics.density;
//        mMaxYOverScrollDistance = (int) (density * MAX_Y_OVERSCROLL_DISTANCE);
//    }
//
//    @Override
//    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent){
   
//        //This is where the magic happens, we have replaced the incoming maxOverScrollY with our own custom variable mMaxYOverScrollDistance;
//        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mMaxYOverScrollDistance, isTouchEvent);
//    }

    public void setAdapter(WheelAdapter adapter) {
        super.setAdapter(adapter);
        wheelAdapter = adapter;
        setCallback(adapter);
    }

    private void setCallback(OnSelectCallback callback) {
        this.callback = callback;
    }

    /**
     * 初始化
     *
     * @param selectView
     * @param rootView
     */
    protected void setUp(View selectView, View rootView) {
        if (null == selectView || null == rootView) {
            return;
        }
        //让listview现实的区域刚好和悬浮框重合
        setPadding(0, selectView.getTop() , 0, rootView.getBottom() - selectView.getBottom() );

        int location1[] = new int[2];
   
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值