jjzjj

java - Android 双向无限滚动列表

coder 2023-12-05 原文

我正在尝试弄清楚如何实现无限滚动列表。它将显示一个日历和事件,它应该从现在或选定的日期开始。它应该可以在过去和 future 的两个方向上滚动。 OnScrollListener 的解决方案 here如果我只需要去 future (索引只会变大),似乎工作得很好。但我不明白我将如何回到过去。

This solution对我来说似乎很浪费。 getView 被调用了数千次。也许 ListView 不是解决方案,我将不得不使用较低级别的代码。有什么想法吗?

编辑:getView 被调用了数千次并不是后一种解决方案的错。然而,它仍然被调用了太多次并且使用了错误的值。如果我这样设置选择:

myList.setSelection(Integer.MAX_VALUE/2)

我收到索引从零开始的 getView 调用。例如,我收到这样的 getView 调用:

getView pos 0
...
getView pos 26

然后

getView pos 1073741823
...
getView pos 1073741847

哪些是正确的。然后:

getView pos 0
...
getView pos 26

再次

这一切都发生在我滚动或触摸屏幕之前。似乎没有多大意义。

最佳答案

下面是这个任务的实现。

EndlessScrollBaseAdapter.java

package com.example.endlessscrollinbothdirections;

import java.util.Map;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.TextView;

/** A child class shall subclass this Adapter and implement method getDataRow(int position,
 * View convertView, ViewGroup parent), which supplies a View present data in a ListRow.
 * This parent Adapter takes care of displaying ProgressBar in a row or indicating that it
 * has reached the last row. */
public abstract class EndlessScrollBaseAdapter<T> extends BaseAdapter implements
        OnScrollListener {
    private int mVisibleThreshold = 5;
    // the main data structure to save loaded data
    protected Map<Integer, T> mItems;
    protected Context mContext;
    // the serverListSize is the total number of items on the server side,
    // which should be returned from the web request results
    protected int mServerListSize = -1;
    // Two view types which will be used to determine whether a row should be displaying
    // data or a Progressbar
    public static final int VIEW_TYPE_LOADING = 0;
    public static final int VIEW_TYPE_ACTIVITY = 1;
    public static final int VIRTUAL_MIDDLE_OFFSET = Integer.MAX_VALUE / 2;

    public EndlessScrollBaseAdapter(Context context, Map<Integer, T> items) {
        mContext = context;
        mItems = items;
    }

    public void setServerListSize(int serverListSize) {
        this.mServerListSize = serverListSize;
    }

    /** disable click events on indicating rows */
    @Override
    public boolean isEnabled(int position) {
        return getItemViewType(position) == EndlessScrollBaseAdapter.VIEW_TYPE_ACTIVITY;
    }

    /** One type is normal data row, the other type is Progressbar */
    @Override
    public int getViewTypeCount() {
        return 2;
    }

    /** the size of the List plus one, the one is the last row, which displays a
     * Progressbar */
    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }

    /** return the type of the row, the last row indicates the user that the ListView is
     * loading more data */
    @Override
    public int getItemViewType(int position) {
        return mItems.containsKey(position
                - EndlessScrollBaseAdapter.VIRTUAL_MIDDLE_OFFSET) ? EndlessScrollBaseAdapter.VIEW_TYPE_ACTIVITY
                : EndlessScrollBaseAdapter.VIEW_TYPE_LOADING;
    }

    @Override
    public T getItem(int position) {
        return mItems.get(position - EndlessScrollBaseAdapter.VIRTUAL_MIDDLE_OFFSET);
    }

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

    /** returns the correct view */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (getItemViewType(position) == EndlessScrollBaseAdapter.VIEW_TYPE_LOADING) {
            return getFooterView(position, convertView, parent);
        }
        return getDataRow(position, convertView, parent);
    };

    /** A subclass should override this method to supply the data row.
     *
     * @param position
     * @param convertView
     * @param parent
     * @return */
    public abstract View getDataRow(int position, View convertView, ViewGroup parent);

    /** returns a View to be displayed in the last row.
     *
     * @param position
     * @param convertView
     * @param parent
     * @return */
    public View getFooterView(int position, View convertView, ViewGroup parent) {
        if (position >= mServerListSize && mServerListSize > 0) {
            // the ListView has reached the last row
            TextView tvLastRow = new TextView(mContext);
            tvLastRow.setHint("Reached the last row.");
            tvLastRow.setGravity(Gravity.CENTER);
            return tvLastRow;
        } else {
            TextView tvLastRow = new TextView(mContext);
            tvLastRow.setHint("Loading...\n position: " + position);
            tvLastRow.setGravity(Gravity.CENTER);
            return tvLastRow;
        }
    }

    // Defines the process for actually loading more data based on page
    public abstract void onLoadMore(int virtualPosition);

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
            int totalItemCount) {
        for (int i = -mVisibleThreshold; i < visibleItemCount + mVisibleThreshold; i++) {
            int virtualPosition = firstVisibleItem
                    - EndlessScrollBaseAdapter.VIRTUAL_MIDDLE_OFFSET + i;
            onLoadMore(virtualPosition);
        }
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }
}

EndlessScrollAdapter.java

package com.example.endlessscrollinbothdirections;

import java.util.Map;
import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class EndlessScrollAdapter extends EndlessScrollBaseAdapter<Integer> {
    public EndlessScrollAdapter(Activity activity, Map<Integer, Integer> list) {
        super(activity, list);
    }

    @Override
    public View getDataRow(int position, View convertView, ViewGroup parent) {
        TextView TextView;
        if (convertView == null) {
            TextView = new TextView(mContext);
        } else {
            TextView = (TextView) convertView;
        }
        TextView.setText("virtualPosition: "
                + (position - EndlessScrollBaseAdapter.VIRTUAL_MIDDLE_OFFSET) + "\n"
                + "row data: "
                + mItems.get(position - EndlessScrollBaseAdapter.VIRTUAL_MIDDLE_OFFSET));
        return TextView;
    }

    @Override
    public void onLoadMore(int virtualPosition) {
        // here you might launch an AsyncTask instead
        if (!mItems.containsKey(virtualPosition)) {
            mItems.put(virtualPosition, virtualPosition);
            notifyDataSetChanged();
        }
    }
}

主 Activity .java

package com.example.endlessscrollinbothdirections;

import java.util.HashMap;
import java.util.Map;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.ListView;

public class MainActivity extends ActionBarActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ListView listView = (ListView) findViewById(R.id.lvItems);
        Map<Integer, Integer> items = new HashMap<Integer, Integer>();
        EndlessScrollAdapter endlessScrollAdapter = new EndlessScrollAdapter(this, items);
        listView.setAdapter(endlessScrollAdapter);
        listView.setSelection(EndlessScrollBaseAdapter.VIRTUAL_MIDDLE_OFFSET);
        listView.setOnScrollListener(endlessScrollAdapter);
    }
}

activity_main.xml

<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/lvItems"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
</ListView>

关于java - Android 双向无限滚动列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22434919/

有关java - Android 双向无限滚动列表的更多相关文章

  1. ruby - 树顶语法无限循环 - 2

    我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He

  2. ruby - RVM 使用列表[0] - 2

    是否有类似“RVMuse1”或“RVMuselist[0]”之类的内容而不是键入整个版本号。在任何时候,我们都会看到一个可能包含5个或更多ruby的列表,我们可以轻松地键入一个数字而不是X.X.X。这也有助于rvmgemset。 最佳答案 这在RVM2.0中是可能的=>https://docs.google.com/document/d/1xW9GeEpLOWPcddDg_hOPvK4oeLxJmU3Q5FiCNT7nTAc/edit?usp=sharing-知道链接的任何人都可以发表评论

  3. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  4. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  5. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  6. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  7. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  8. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  9. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  10. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

随机推荐