水平ListView

/* * HorizontalListView.java v1.5 * *  * The MIT License * Copyright (c) 2011 Paul Soucy ([email protected]) *  * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: *  * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. *  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */

import java.util.LinkedList;import java.util.Queue;import android.content.Context;import android.database.DataSetObserver;import android.graphics.Rect;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.GestureDetector.OnGestureListener;import android.view.MotionEvent;import android.view.View;import android.widget.AdapterView;import android.widget.ListAdapter;import android.widget.Scroller;

public class HorizontalListView extends AdapterView<ListAdapter> {

    public boolean mAlwaysOverrideTouch = true;    protected ListAdapter mAdapter;    private int mLeftViewIndex = -1;    private int mRightViewIndex = 0;    protected int mCurrentX;    protected int mNextX;    private int mMaxX = Integer.MAX_VALUE;    private int mDisplayOffset = 0;    protected Scroller mScroller;    private GestureDetector mGesture;    private Queue<View> mRemovedViewQueue = new LinkedList<View>();    private OnItemSelectedListener mOnItemSelected;    private OnItemClickListener mOnItemClicked;    private OnItemLongClickListener mOnItemLongClicked;    private boolean mDataChanged = false;

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

    private synchronized void initView() {        mLeftViewIndex = -1;        mRightViewIndex = 0;        mDisplayOffset = 0;        mCurrentX = 0;        mNextX = 0;        mMaxX = Integer.MAX_VALUE;        mScroller = new Scroller(getContext());        mGesture = new GestureDetector(getContext(), mOnGesture);    }

    @Override    public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) {        mOnItemSelected = listener;    }

    @Override    public void setOnItemClickListener(AdapterView.OnItemClickListener listener) {        mOnItemClicked = listener;    }

    @Override    public void setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener) {        mOnItemLongClicked = listener;    }

    private DataSetObserver mDataObserver = new DataSetObserver() {

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

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

    };

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

    @Override    public View getSelectedView() {        return null;    }

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

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

    @Override    public void setSelection(int position) {    }

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

        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 oldCurrentX = mCurrentX;            initView();            removeAllViewsInLayout();            mNextX = oldCurrentX;            mDataChanged = false;        }

        if (mScroller.computeScrollOffset()) {            int scrollx = mScroller.getCurrX();            mNextX = scrollx;        }        // 滑动超出区域        if (mNextX <= 0) {            mNextX = 0;            mScroller.forceFinished(true);        }        if (mNextX >= mMaxX) {            mNextX = mMaxX;            mScroller.forceFinished(true);        }

        int dx = mCurrentX - mNextX;

        removeNonVisibleItems(dx);        fillList(dx);        positionItems(dx);

        mCurrentX = mNextX;

        if (!mScroller.isFinished()) {            post(new Runnable() {

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

        }    }

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

        edge = 0;        child = getChildAt(0);        if (child != null) {            edge = child.getLeft();        }        fillListLeft(edge, dx);

    }

    private void fillListRight(int rightEdge, final int dx) {        while (rightEdge + dx < getWidth() && mRightViewIndex < mAdapter.getCount()) {            View child = mAdapter.getView(mRightViewIndex, mRemovedViewQueue.poll(), this);            addAndMeasureChild(child, -1);            rightEdge += child.getMeasuredWidth();

            if (mRightViewIndex == mAdapter.getCount() - 1) {                mMaxX = mCurrentX + rightEdge - getWidth();            }

            if (mMaxX < 0) {                mMaxX = 0;            }            mRightViewIndex++;        }

    }

    private void fillListLeft(int leftEdge, final int dx) {        while (leftEdge + dx > 0 && mLeftViewIndex >= 0) {            View child = mAdapter.getView(mLeftViewIndex, mRemovedViewQueue.poll(), this);            addAndMeasureChild(child, 0);            leftEdge -= child.getMeasuredWidth();            mLeftViewIndex--;            mDisplayOffset -= child.getMeasuredWidth();        }    }

    private void removeNonVisibleItems(final int dx) {        View child = getChildAt(0);        while (child != null && child.getRight() + dx <= 0) {            mDisplayOffset += child.getMeasuredWidth();            mRemovedViewQueue.offer(child);            removeViewInLayout(child);            mLeftViewIndex++;            child = getChildAt(0);

        }

        child = getChildAt(getChildCount() - 1);        while (child != null && child.getLeft() + dx >= getWidth()) {            mRemovedViewQueue.offer(child);            removeViewInLayout(child);            mRightViewIndex--;            child = getChildAt(getChildCount() - 1);        }    }

    private void positionItems(final int dx) {        if (getChildCount() > 0) {            mDisplayOffset += dx;            int left = mDisplayOffset;            for (int i = 0; i < getChildCount(); i++) {                View child = getChildAt(i);                int childWidth = child.getMeasuredWidth();                child.layout(left, 0, left + childWidth, child.getMeasuredHeight());                left += childWidth + child.getPaddingRight();            }        }    }

    public synchronized void scrollToZero() {        mCurrentX = 0;    }

    public synchronized void scrollToScreen(int x) {       mCurrentX += x;    }

    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        boolean handled = super.dispatchTouchEvent(ev);        handled |= mGesture.onTouchEvent(ev);        return handled;    }

    protected boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {        synchronized (HorizontalListView.this) {            mScroller.fling(mNextX, 0, (int) -velocityX, 0, 0, mMaxX, 0, 0);        }        requestLayout();

        return true;    }

    protected boolean onDown(MotionEvent e) {        mScroller.forceFinished(true);        return true;    }

    private OnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener() {

        @Override        public boolean onDown(MotionEvent e) {            return HorizontalListView.this.onDown(e);        }

        @Override        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {            return HorizontalListView.this.onFling(e1, e2, velocityX, velocityY);        }

        @Override        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

            synchronized (HorizontalListView.this) {                mNextX += (int) distanceX;            }            requestLayout();

            return true;        }

        @Override        public boolean onSingleTapConfirmed(MotionEvent e) {            for (int i = 0; i < getChildCount(); i++) {                View child = getChildAt(i);                if (isEventWithinView(e, child)) {                    if (mOnItemClicked != null) {                        mOnItemClicked.onItemClick(HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId(mLeftViewIndex + 1 + i));                    }                    if (mOnItemSelected != null) {                        mOnItemSelected.onItemSelected(HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId(mLeftViewIndex + 1 + i));                    }                    break;                }

            }            return true;        }

        @Override        public void onLongPress(MotionEvent e) {            int childCount = getChildCount();            for (int i = 0; i < childCount; i++) {                View child = getChildAt(i);                if (isEventWithinView(e, child)) {                    if (mOnItemLongClicked != null) {                        mOnItemLongClicked.onItemLongClick(HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId(mLeftViewIndex + 1 + i));                    }                    break;                }

            }        }

        private boolean isEventWithinView(MotionEvent e, View child) {            Rect viewRect = new Rect();            int[] childPosition = new int[2];            child.getLocationOnScreen(childPosition);            int left = childPosition[0];            int right = left + child.getWidth();            int top = childPosition[1];            int bottom = top + child.getHeight();            viewRect.set(left, top, right, bottom);            return viewRect.contains((int) e.getRawX(), (int) e.getRawY());        }    };

   public int getmLeftViewIndex() {      return mLeftViewIndex;   }

   public int getmRightViewIndex() {      return mRightViewIndex;   }

}
时间: 2024-10-19 20:38:06

水平ListView的相关文章

横向滑动的listview效果的实现方法,scrollview嵌套水平滑动的listview卡顿的解决方法

很多时候,界面需要实现横向滑动的listview效果.网络上有一种方法,自定义了HorizontalListView,用法同正常的listview,可实现水平滑动效果. 但是如果一个界面 为垂直滑动的scrollview嵌套水平滑动的listview的时候,滑动水平listview的时候,会很卡.我最近就遇到了这样的问题,一直把思路放在监听水平和垂直滑动手势,想实现滑动角度小于45的时候 垂直的scrollview 滑动效果被禁止.但是一直没有研究出来. 于是一个偶然的机会,灵光一闪,想到用Ho

与listView功能相近的gallery,主讲gallery

最近做项目要用到横向的listvew,找了下却实在没有水平方向的listview, 就想到了gallery,虽然Gallery is deprecated,但它的作用个人觉得还是很不错的, (因本人不会写自定义的水平listview) gallery实现的效果涂如下: 给gallery添加代码的只要代码如下: protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setCo

多个ListView同步滚动

引言: 开发的过程中可能会遇到2个或者更多的listview为了保持对应关系一起滚动的情况,这篇文章给大家演示这种效果. 效果: 实现原理: 在滚动其中任何一个ListView的时候,同时设置其他ListView的滚动位置.示例中使用的是水平ListView. HListView的项目托管地址是:https://github.com/sephiroth74/HorizontalVariableListView   有兴趣的可以研究一下 步骤: 1.为了能实现同时滚动的情况,有一些条件,首先是HL

android源码大放送(实战开发必备),免费安卓demo源码,例子大全文件详细列表

免费安卓demo源码,例子大全文件详细列表 本列表源码永久免费下载地址:http://www.jiandaima.com/blog/android-demo 卷 yunpan 的文件夹 PATH 列表 卷序列号为 0000-73EC E:. │ jiandaima.com文件列表生成.bat │ 例子大全说明.txt │ 本例子永久更新地址~.url │ 目录列表2016.03.10更新.txt │ ├─前台界面 │ ├─3D标签云卡片热门 │ │ Android TagCloudView云标签

HorizontalListView中使用notifyDataSetChanged()和notifyDataSetInvalidated()

今天在项目中用到了水平ListView控件HorizontalListView,也是我在网上找的个开源HorizontalListView直接在项目中使用.我是把HorizontalListView放在了可以切换的Tab页面中的,在使用的时候发现了一个小问题:在切换TAB页时,更新对应的adapter数据时,调用adapter的notifyDataSetChanged()方法发现达不到想要的效果,后来在网上查了下,才知道: 横向listview中notifyDataSetInvalidated(

Android HorizontalScrollView 水平滑动 在listview上面动态添加图片

Android HorizontalScrollView   水平滑动    listview 上动态添加图片 最近遇到了个 在listview展示广告的需要动态添加图片 如图: 使用了 horizontalScrollView   在listview上进行添加 java代码: package com.baozi.bzhorizontalscrollview; import java.util.ArrayList; import android.app.Activity; import andr

ListVIew中包含水平滑动控件,左右滑动时容易触发上下滑动

自定义ListView import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.widget.ListView; public class LiveCustomListView extends ListView { public LiveCustomListView(Context context) { super(context)

7-2 基于ListView实现水平和垂直方式滚动的列表

主要学习ListView的水平列表和垂直方向的布局. 运行这段代码,查看效果 水平布局 这里设置了滚动的方向 只有一行代码的改动 按住文字才可以左右滚动. 可以左右滑动 给每一个item设置了160的宽度,然后,设置了右边的间距是5. 如果我们要为ListView设置高度的话.这里给item设置高度是无效的 只能设置ListView上面的Container的高度. 如果我们这里把ListView的高度取消. 我们的item就沾满了整个屏幕 如果给这个item设置高度是不会起作用的. 所以推荐大家

ListView 基础列表组件、水平 列表组件、图标组件

一.Flutter 列表组件概述 列表布局是我们项目开发中最常用的一种布局方式.Flutter 中我们可以通过 ListView 来定义 列表项,支持垂直和水平方向展示.通过一个属性就可以控制列表的显示方向.列表有一下 分类: 1.垂直列表 2.垂直图文列表 3.水平列表 4.动态列表 5.矩阵式列表 二.Flutter 列表参数 三.Flutter 基本列表 四.Flutter 水平列表 ListView( scrollDirection: Axis.horizontal ) 原文地址:htt