首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ListView内部的HorizontalListView

ListView内部的HorizontalListView
EN

Stack Overflow用户
提问于 2013-03-03 08:08:41
回答 1查看 473关注 0票数 1

我正在尝试将HorizontalListView (http://www.dev-smart.com/archives/34)添加到ListView。ListView使用适配器动态附加新的HorizontalListView行,以进行连续的垂直滚动。

它几乎可以工作:问题是,当滚动HorizontalListView时,ListView会自动向上或向下滚动,并将HorizontalListView放在视口的顶部或底部边缘,具体取决于它离哪个最近。如何停止HorizontalListView行在滚动中对齐到位?

我使用HorizontalListView作为我的“VerticalScrollView”的引用:

代码语言:javascript
复制
public class VerticalScrollView extends ListView {

public static interface ScrollListener {
    void onScrollEnd();
}

public VerticalScrollView(Context context) {
    super(context);
    initView();
}

public VerticalScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initView();
}

private synchronized void initView() {
    mTopViewIndex = -1;
    mBottomViewIndex = 0;
    mDisplayOffset = 0;
    mCurrentY = 0;
    mNextY = 0;
    mMaxY = Integer.MAX_VALUE;
    mScroller = new Scroller(getContext());
    setFadingEdgeLength(0);
    setItemsCanFocus(false);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN:
        mXDistance = mYDistance = 0f;
        mLastX = ev.getX();
        mLastY = ev.getY();
        break;
    case MotionEvent.ACTION_MOVE:
        final float curX = ev.getX();
        final float curY = ev.getY();
        mXDistance += Math.abs(curX - mLastX);
        mYDistance += Math.abs(curY - mLastY);
        mLastX = curX;
        mLastY = curY;
        if(mXDistance > mYDistance) {
            return false;
        }
    }
    return super.onInterceptTouchEvent(ev);
}

@Override
public ListAdapter getAdapter() {
    return mAdapter;
}

@Override
public View getSelectedView() {
    //TODO: implement
    return null;
}

@Override
public void setAdapter(ListAdapter adapter) {
    if(mAdapter != null) {
        mAdapter.unregisterDataSetObserver(mDataObserver);
    }
    mAdapter = adapter;
    mAdapter.registerDataSetObserver(mDataObserver);
    reset();
    super.setAdapter(adapter);
}

private synchronized void reset(){
    initView();
    removeAllViewsInLayout();
    requestLayout();
}

@Override
public void setSelection(int position) {
    //TODO: implement
}

private void addAndMeasureChild(final View child, int viewPos) {
    android.view.ViewGroup.LayoutParams params = child.getLayoutParams();
    if(params == null) {
        params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

    addViewInLayout(child, viewPos, params, true);
    child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
            MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
}

@Override
protected synchronized void onLayout(
        boolean changed,
        int left,
        int top,
        int right,
        int bottom) {
    super.onLayout(changed, left, top, right, bottom);

    if(mAdapter == null){
        return;
    }

    if(mDataChanged){
        int oldCurrentY = mCurrentY;
        initView();
        removeAllViewsInLayout();
        mNextY = oldCurrentY;
        mDataChanged = false;
    }

    if(mScroller.computeScrollOffset()){
        int scrollY = mScroller.getCurrY();
        mNextY = scrollY;
    }

    if(mNextY <= 0){
        mNextY = 0;
        mScroller.forceFinished(true);
    }
    if(mNextY >= mMaxY) {
        mNextY = mMaxY;
        mScroller.forceFinished(true);
    }

    int dy = mCurrentY - mNextY;

    removeNonVisibleItems(dy);
    fillList(dy);
    positionItems(dy);

    mCurrentY = mNextY;

    if(!mScroller.isFinished()){
        post(mRequestLayoutRunnable);
    }
}

private void fillList(final int dy) {
    int edge = 0;
    View child = getChildAt(getChildCount()-1);
    if(child != null) {
        edge = child.getBottom();
    }
    fillListBottom(edge, dy);

    edge = 0;
    child = getChildAt(0);
    if(child != null) {
        edge = child.getTop();
    }
    fillListTop(edge, dy);
}

private void fillListBottom(int bottomEdge, final int dy) {
    while(bottomEdge + dy < getHeight() && mBottomViewIndex < mAdapter.getCount()) {

        View child = mAdapter.getView(mBottomViewIndex, mRemovedViewQueue.poll(), this);
        addAndMeasureChild(child, -1);
        bottomEdge += child.getMeasuredHeight();

        if(mBottomViewIndex == mAdapter.getCount()-1) {
            mMaxY = mCurrentY + bottomEdge - getHeight();
        }

        if (mMaxY < 0) {
            mMaxY = 0;
        }
        mBottomViewIndex++;
    }
}

private void fillListTop(int topEdge, final int dy) {
    while(topEdge + dy > 0 && mTopViewIndex >= 0) {
        View child = mAdapter.getView(mTopViewIndex, mRemovedViewQueue.poll(), this);
        addAndMeasureChild(child, 0);
        topEdge -= child.getMeasuredHeight();
        mTopViewIndex--;
        mDisplayOffset -= child.getMeasuredHeight();
    }
}

private void removeNonVisibleItems(final int dy) {
    View child = getChildAt(0);
    while(child != null && child.getBottom() + dy <= 0) {
        mDisplayOffset += child.getMeasuredHeight();
        mRemovedViewQueue.offer(child);
        removeViewInLayout(child);
        mTopViewIndex++;
        child = getChildAt(0);

    }

    child = getChildAt(getChildCount()-1);
    while(child != null && child.getLeft() + dy >= getHeight()) {
        mRemovedViewQueue.offer(child);
        removeViewInLayout(child);
        mBottomViewIndex--;
        child = getChildAt(getChildCount()-1);
    }
}

private void positionItems(final int dy) {
    if(getChildCount() > 0){
        mDisplayOffset += dy;
        int top = mDisplayOffset;
        for(int i=0;i<getChildCount();i++){
            View child = getChildAt(i);
            int childHeight = child.getMeasuredHeight();
            child.layout(0, top, child.getMeasuredWidth(), top + childHeight);
            top += childHeight + child.getPaddingBottom();
        }
    }
}

public synchronized void scrollTo(int y) {
    mScroller.startScroll(0, mNextY, 0, y - mNextY);
    requestLayout();
}

public boolean mAlwaysOverrideTouch = true;
protected ListAdapter mAdapter;
private int mTopViewIndex = -1;
private int mBottomViewIndex = 0;
protected int mCurrentY;
protected int mNextY;
private int mMaxY = Integer.MAX_VALUE;
private int mDisplayOffset = 0;
protected Scroller mScroller;
private Queue<View> mRemovedViewQueue = new LinkedList<View>();
private boolean mDataChanged = false;
private float mXDistance;
private float mYDistance;
private float mLastX;
private float mLastY;

private Runnable mRequestLayoutRunnable = new Runnable(){

    @Override
    public void run() {
        requestLayout();
    }
};

private DataSetObserver mDataObserver = new DataSetObserver() {

    @Override
    public void onChanged() {
        synchronized(VerticalScrollView.this){
            mDataChanged = true;
        }
        invalidate();
        requestLayout();
    }

    @Override
    public void onInvalidated() {
        reset();
        invalidate();
        requestLayout();
    }
};

编辑:通过使用普通的ListView而不是我的自定义VerticalScrollView,我可以让它完美地工作。当用户向下滚动时,我将从网络填充ListView。如何管理列表项视图,使其不会耗尽内存?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-03-04 03:26:02

通过将HorizontalListViews附加到ListView,我能够获得我想要的行为。然后,我包装了我的适配器,它创建了一个带有EndlessAdapter的HorizontalListViews,用于连续滚动:

https://github.com/commonsguy/cwac-endless

我确保在适配器的getView方法中循环使用视图来解决内存问题。但是,如果我的模型层在堆上占用了太多空间,我仍然会耗尽内存。

有没有人知道一个好的框架,可以在模型对象离开屏幕时剔除它们,并在需要再次显示时重新加载它们?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15180942

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档