可横向或部分横向滑动的列表实现

      先看下效果:


    首先需要构造一个header部分,header部分分为固定header和滑动header,滑动header采用横向scrollview实现:

private void bindHeader(){
    headerLiearLayout = new LinearLayout(context);
headerLiearLayout.setOrientation(HORIZONTAL);
LinearLayout.LayoutParams params = new LayoutParams(dp2px(75),rowHeight);
params.gravity = Gravity.CENTER;
    for (String str:fixedList){
        TextView tv = new TextView(context);
tv.setText(str);
tv.setTextColor(Color.WHITE);
tv.setGravity(Gravity.CENTER);
headerLiearLayout.addView(tv,params);
}
    rightHeader = new LinearLayout(context);
    for(String str:movedList){
        TextView tv = new TextView(context);
tv.setText(str);
tv.setTextColor(Color.WHITE);
tv.setGravity(Gravity.CENTER);
rightHeader.addView(tv,params);
}
    headerLiearLayout.addView(rightHeader);
addView(headerLiearLayout);
}

下面列表部分使用listview:

private void buildListView(){
    movableLayout = new LinearLayout(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
listView = new ListView(context);
movableLayout.setLayoutParams(params);
listView.setBackgroundColor(0xff9f9f9f);
listView.setLayoutParams(params);
movableLayout.addView(listView,params);
addView(movableLayout,params);
}

布局模式完成,现在关键是如何实现横向滑动,且只是部分内容横向滑动。

由于我们自己需要主动去滑动,因此我们需要监听滑动事件,并能区分是横向动作还是竖直动作,如果是竖直动作的话只需要交给listview实现就可以了,横向则需要我们自己主动去滑动部分子view,以下为事件的拦截及处理机制:

扫描二维码关注公众号,回复: 317582 查看本文章
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    int action = ev.getAction();
    if(action == MotionEvent.ACTION_MOVE &&
            (mTouchState != TOUCH_STATE_RESET)){
        return true;
}
    int x = (int) ev.getX();
    int y = (int) ev.getY();
    switch (action){
        case MotionEvent.ACTION_DOWN:
            lastX = x;
lastY = y;
mTouchState = scroller.isFinished()?TOUCH_STATE_RESET:TOUCH_STATE_SCRONING;
            break;
        case MotionEvent.ACTION_MOVE:
            int deltaX = (int)Math.abs(lastX - x);
            int deltaY = (int)Math.abs(lastY - y);
            if(deltaX > deltaY ){
                mTouchState = TOUCH_STATE_SCRONING;
}
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            mTouchState = TOUCH_STATE_RESET;
            break;
}
    return mTouchState != TOUCH_STATE_RESET;

}

@Override
public boolean onTouchEvent(MotionEvent event) {
    int action = event.getAction();
    int x = (int)event.getX();

    if (velocityTracker == null) {
        velocityTracker = VelocityTracker.obtain();
}
    velocityTracker.addMovement(event);
    switch (action){
        case MotionEvent.ACTION_DOWN:
            lastX = x;
            break;
        case MotionEvent.ACTION_MOVE:
            int deltaX = (int)(lastX - x);
lastX = x;
            if(scroller != null && rightHeader != null){
                scroller.startScroll((int)(rightHeader.getScrollX()),0,deltaX,0,0);
invalidate();
}
            break;
        case MotionEvent.ACTION_UP:
            final VelocityTracker vt = velocityTracker;
vt.computeCurrentVelocity(1000);
            int velocityX = (int) vt.getXVelocity();
            int max = rightHeader.getChildAt(0).getWidth() * rightHeader.getChildCount()
                    - rightHeader.getWidth();
scroller.fling(rightHeader.getScrollX(),0,-velocityX,0,0,max,0,0);
invalidate();
            if (velocityTracker != null) {
                velocityTracker.recycle();
velocityTracker = null;
}
            mTouchState = TOUCH_STATE_RESET;
            break;
        case MotionEvent.ACTION_CANCEL:
            mTouchState = TOUCH_STATE_RESET;
            break;
}
    return true;
}

    Scroll 是一个滚动控制器,在这里需要用它来实现横向滑动。注意startscroll和fling函数,看名字就知道了这里不多述,重要的一点是调用了该函数后,主动刷新view会条用completscroll函数(不明白的可以查看view的刷新机制),在这个函数中是实现真正的滑动部分:

@Override
public void computeScroll() {
    if(scroller.computeScrollOffset()){
        int scrollX = scroller.getCurrX();
        final int maxX = rightHeader.getChildAt(0).getWidth() * rightHeader.getChildCount() - rightHeader.getWidth();
scrollX = Math.max(0,scrollX);
scrollX = Math.min(maxX,scrollX);
rightHeader.scrollTo(scrollX,0);
scrollChildTo(scrollX);
}
}

在scrollchildTo函数中完成对listview中各个child的部分view的横向滑动:

protected void scrollChildTo(int mScrollX)
{
    if(listView != null)
    {
        View temp = null;
        int nChildCount = listView.getChildCount();
        for(int i = 0; i < nChildCount; i++)
        {
            temp = listView.getChildAt(i);

            int size =  ((ViewGroup) temp).getChildCount();
            for(int j = 0;j < size;j ++){
                View item = ((ViewGroup) temp).getChildAt(j);
                if(item instanceof LinearLayout) {
                    item.scrollTo(mScrollX, 0);
}

            }

        }
    }
}

这里的item布局可以看出,横向滚动部分使用linearlayout部分包裹,因此只需要让该view滚动即可.

最后就是适配器的处理了,基本上adapter跟普通的一样,不过有一点需要注意的是view的重用机制会造成最后一条滚动异常,我们需要加上一段矫正代码:

private void adjustMoved(View view) {
    View moveView = (View) view.findViewById(R.id.moveLayout);
    int moveX1 = moveView.getScrollX();
    int moveX2 = ajustView.getScrollX();
    if(moveX1 != moveX2){
        moveView.scrollTo(ajustView.getScrollX(),0);
}
}

基本实现基本完成了,剩下的事情就是填充数据展示之类的。

抱歉,公司不能传代码,如果有需要的可以给我留言,我重新写一个完整的。

猜你喜欢

转载自java-cofi.iteye.com/blog/2286304
今日推荐