热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android中实现水平滑动(横向滑动)ListView示例

这篇文章主要介绍了Android中实现水平滑动(横向滑动)ListView示例,本文用自己封装一个控件的方法解决了这个需求,需要的朋友可以参考下

水平的ListView-HorizontalListView的使用

Android中ListView默认的是竖直方向的滑动,由于项目的需求,需要ListView是水平滑动的。有很多的方式可以实现,但是比较好的一种方式就是自己封装一个控件,使用方式和ListView的使用方式是一样的。需要完善的地方:获取到的图片大小没有处理。在界面上展示的是图片的原大小。为了更好的展示效果,应该压缩成统一的尺寸。

HorizontalListView.java 代码如下:

/**
 * 横向的ListView
 * 
 * * @author scd
 * 
 */
public class HorizontalListView extends AdapterView {

  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 mRemovedViewQueue = new LinkedList();
  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() {
    // TODO: implement
    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) {
    // TODO: implement
  }

  private void addAndMeasureChild(final View child, int viewPos) {
    LayoutParams params = child.getLayoutParams();
    if (params == null) {
      params = new LayoutParams(LayoutParams.FILL_PARENT,
          LayoutParams.FILL_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 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  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 

适配器 HorizontalListViewAdapter .java如下:

public class HorizontalListViewAdapter extends BaseAdapter {
  /** 上下文 */
  private Context mContext;
  /** 图像数据源 */
  private ArrayList> mImageList;

  /** 数据源 */
  private ArrayList> mTextList;
  /** Image */
  private static String IMAGE = "ic_";

  private Map mMap = null;

  /** 构造方法 */
  public HorizontalListViewAdapter(Context context) {
    this.mCOntext= context;
    initData();
  }

  /** 初始化数据 */
  public void initData() {
    mImageList = new ArrayList>();
    /*
     * 反射技术
     */
    Class<&#63;> imageClzz = R.drawable.class;
    R.drawable instance = new R.drawable();
    // 取得drawable类中所有的字段
    Field[] fields = imageClzz.getDeclaredFields();
    for (Field field : fields) {
      // 获得字段的名字
      String name = field.getName();
      if (name != null && name.startsWith(IMAGE)) {
        try {
          mMap = new HashMap();
          mMap.put(IMAGE, (Integer) field.get(instance));
          mImageList.add(mMap);
        } catch (IllegalAccessException e) {
          e.printStackTrace();
        }
      }

    }
  }


  @Override
  public int getCount() {
    return mImageList.size();
  }

  @Override
  public Map getItem(int position) {

    return mImageList == null &#63; null : mImageList.get(position);
  }

  @Override
  public long getItemId(int position) {
    return position;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolder holder;
    if (cOnvertView== null) {
      holder = new ViewHolder();
      cOnvertView= LayoutInflater.from(mContext).inflate(
          R.layout.horizontal_list_item, null);
      holder.mImage = (ImageView) convertView
          .findViewById(R.id.iv_list_item);
      holder.mTitle = (TextView) convertView
          .findViewById(R.id.tv_list_item);
      convertView.setTag(holder);
    } else {
      holder = (ViewHolder) convertView.getTag();
    }

    if (position == mSelectIndex) {
      convertView.setSelected(true);
    } else {
      convertView.setSelected(false);
    }
    holder.mImage.setImageResource(getItem(position).get(IMAGE));
    return convertView;
  }

  private class ViewHolder {
    /** 图像 */
    private ImageView mImage;
  }
}


推荐阅读
  • 2023 ARM嵌入式系统全国技术巡讲旨在分享ARM公司在半导体知识产权(IP)领域的最新进展。作为全球领先的IP提供商,ARM在嵌入式处理器市场占据主导地位,其产品广泛应用于90%以上的嵌入式设备中。此次巡讲将邀请来自ARM、飞思卡尔以及华清远见教育集团的行业专家,共同探讨当前嵌入式系统的前沿技术和应用。 ... [详细]
  • Android 九宫格布局详解及实现:人人网应用示例
    本文深入探讨了人人网Android应用中独特的九宫格布局设计,解析其背后的GridView实现原理,并提供详细的代码示例。这种布局方式不仅美观大方,而且在现代Android应用中较为少见,值得开发者借鉴。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 本文介绍了如何使用jQuery根据元素的类型(如复选框)和标签名(如段落)来获取DOM对象。这有助于更高效地操作网页中的特定元素。 ... [详细]
  • 本文将详细介绍如何使用剪映应用中的镜像功能,帮助用户轻松实现视频的镜像效果。通过简单的步骤,您可以快速掌握这一实用技巧。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 本文介绍如何在 Xcode 中使用快捷键和菜单命令对多行代码进行缩进,包括右缩进和左缩进的具体操作方法。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • 在Linux系统中配置并启动ActiveMQ
    本文详细介绍了如何在Linux环境中安装和配置ActiveMQ,包括端口开放及防火墙设置。通过本文,您可以掌握完整的ActiveMQ部署流程,确保其在网络环境中正常运行。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • 如何在WPS Office for Mac中调整Word文档的文字排列方向
    本文将详细介绍如何使用最新版WPS Office for Mac调整Word文档中的文字排列方向。通过这些步骤,用户可以轻松更改文本的水平或垂直排列方式,以满足不同的排版需求。 ... [详细]
  • 本文总结了在使用Ionic 5进行Android平台APK打包时遇到的问题,特别是针对QRScanner插件的改造。通过详细分析和提供具体的解决方法,帮助开发者顺利打包并优化应用性能。 ... [详细]
  • 理解存储器的层次结构有助于程序员优化程序性能,通过合理安排数据在不同层级的存储位置,提升CPU的数据访问速度。本文详细探讨了静态随机访问存储器(SRAM)和动态随机访问存储器(DRAM)的工作原理及其应用场景,并介绍了存储器模块中的数据存取过程及局部性原理。 ... [详细]
  • 360SRC安全应急响应:从漏洞提交到修复的全过程
    本文详细介绍了360SRC平台处理一起关键安全事件的过程,涵盖从漏洞提交、验证、排查到最终修复的各个环节。通过这一案例,展示了360在安全应急响应方面的专业能力和严谨态度。 ... [详细]
author-avatar
夏雨之唯美
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有