草庐IT

Android - 可扩展 ListView 的更好替代方案?

coder 2023-11-27 原文

我有一个从 Web 服务 JSON 加载的项目列表。这些项目中的每一个都有自己的子项目列表。每个项目都有许多 TextView 。子项的数量动态变化,由多个 TextView 组成。有时有几十个项目可能有数百个子项目。我希望所有信息始终可见,即我实际上不需要可扩展 ListView 的“可扩展”部分,但这似乎是获取子项和组布局的最简单方法。

Item1
  sub item 1
  sub item 2

Item 2
  sub item 1
  sub item 2
  sub item 3

etc

我目前已经实现了一个可扩展的 ListView 并强制组始终被扩展。这有效,但是滚动速度非常慢,不仅在模拟器上而且在我的银河系 s2 上。
我想知道是否有更好的方法来实现这一目标?
我考虑过单个 ListView 并将子项中的字符串连接到单个 TextView 中,但我认为这在美学上并不令人愉悦,而且我将无法获得我想要的布局。
我想知道是否有一种方法可以覆盖改编的 ListView ,以便其中一个项目本身就是其他项目的数组。适配器可以遍历该数组并动态创建新的 TextView 。我想这就是可扩展 ListView 正在做的事情,所以也许这最终会导致同样多的滞后滚动。

非常感谢任何帮助

最佳答案

您可以使用 ListView 和自定义适配器类来实现。

请注意,适配器具有您可以覆盖的方法 int getViewTypeCount()int getItemViewType(int position)

查看列表 map 中数据集的示例实现

public abstract class ExampleMapAdapter<V extends Map<?, ? extends List<?>>> extends BaseAdapter {

    public static final int VIEW_TYPE_HEADER = 0;
    public static final int VIEW_TYPE_LISTITEM = 1;

    protected V data;
    protected int[] sectionsStart;
    protected Object[] sections;
    protected int count;

    public ExampleMapAdapter(V data) {
        this.data = data;
        onSetData();
    }

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public Object getItem(int position) {
        int sectionIndex = getSectionForPosition(position);
        int innerIndex = position - sectionsStart[sectionIndex];
        if(innerIndex == 0) { //head
            return sections[sectionIndex];
        }
        else { //values
            return data.get(sections[sectionIndex]).get(innerIndex - 1);
        }
    }

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

    @Override
    public int getViewTypeCount() {
        return 2;
    }

    @Override
    public int getItemViewType(int position) {
        return Arrays.binarySearch(sectionsStart, position) < 0 ? VIEW_TYPE_LISTITEM : VIEW_TYPE_HEADER;
    }

    public int getPositionForSection(int section) {
        return sectionsStart[section];
    }

    public int getSectionForPosition(int position) {
        int section = Arrays.binarySearch(sectionsStart, position);
        return section < 0 ? -section - 2 : section;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(getItemViewType(position) == VIEW_TYPE_HEADER) {
            return getHeaderView(position, convertView, parent);
        }
        else {
            return getListItemView(position, convertView, parent);
        }
    }

    @Override
    public void notifyDataSetInvalidated() {
        data = null;
        onSetData();
        super.notifyDataSetInvalidated();
    }

    @Override
    public void notifyDataSetChanged() {
        onSetData();
        super.notifyDataSetChanged();
    }

    protected void onSetData() {
        if(data == null) {
            sectionsStart = null;
            sections = null;
            count = 0;
        }
        else {
            sectionsStart = new int[data.size()];
            sections = data.keySet().toArray(new Object[data.size()]);
            count = 0;
            int i = 0;
            for(List<?> v : data.values()) {
                sectionsStart[i] = count;
                i++;
                count += 1 + v.size();
            }
        }
    }

    protected abstract View getHeaderView(int position, View convertView, ViewGroup parent);

    protected abstract View getListItemView(int position, View convertView, ViewGroup parent);
}

和用法示例:

public class ExampleActivity extends Activity {

    class SubItem {
        public final String text;
        public final int number;
        public final boolean checked;
        public SubItem(String text, int number, boolean checked) {
            this.text = text;
            this.number = number;
            this.checked = checked;
        }
    }

    //use LinkedHashMap or TreeMap as other map implementations may not keep key's order
    final Map<String, List<SubItem>> map = new LinkedHashMap<String, List<SubItem>>();
    {
        List<SubItem> list = new ArrayList<SubItem>();
        list.add(new SubItem("sub item", 1, false));
        list.add(new SubItem("sub item", 2, true));
        map.put("Item1", list);
        list = new ArrayList<SubItem>();
        list.add(new SubItem("sub item", 1, true));
        list.add(new SubItem("sub item", 2, false));
        list.add(new SubItem("sub item", 3, false));
        map.put("Item2", list);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        ListView vList = new ListView(this);
        vList.setAdapter(new ExampleMapAdapter<Map<String, List<SubItem>>>(map) {

            @Override
            protected View getHeaderView(int position, View convertView,
                    ViewGroup parent) {
                TextView v = convertView == null ? 
                        new TextView(parent.getContext()) : (TextView) convertView;
                v.setText((String) getItem(position));
                return v;
            }

            @Override
            protected View getListItemView(int position, View convertView,
                    ViewGroup parent) {
                CheckBox v = convertView == null ? 
                        new CheckBox(parent.getContext()) : (CheckBox) convertView;
                SubItem item = (SubItem) getItem(position);
                v.setText(item.text + " " + item.number);
                v.setChecked(item.checked);
                return v;
            }
        });
        setContentView(vList);
    }
}

关于Android - 可扩展 ListView 的更好替代方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12972398/

有关Android - 可扩展 ListView 的更好替代方案?的更多相关文章

  1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  2. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  3. ruby-on-rails - 更好的替代方法 try( :output). try( :data). try( :name)? - 2

    “输出”是一个序列化的OpenStruct。定义标题try(:output).try(:data).try(:title)结束什么会更好?:) 最佳答案 或者只是这样:deftitleoutput.data.titlerescuenilend 关于ruby-on-rails-更好的替代方法try(:output).try(:data).try(:name)?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.c

  4. ruby-on-rails - 使用 ruby​​ 将多个实例变量转换为散列的更好方法? - 2

    我收到格式为的回复#我需要将其转换为哈希值(针对活跃商家)。目前我正在遍历变量并执行此操作:response.instance_variables.eachdo|r|my_hash.merge!(r.to_s.delete("@").intern=>response.instance_eval(r.to_s.delete("@")))end这有效,它将生成{:first="charlie",:last=>"kelly"},但它似乎有点hacky和不稳定。有更好的方法吗?编辑:我刚刚意识到我可以使用instance_variable_get作为该等式的第二部分,但这仍然是主要问题。

  5. c - mkmf 在编译 C 扩展时忽略子文件夹中的文件 - 2

    我想这样组织C源代码:+/||___+ext||||___+native_extension||||___+lib||||||___(Sourcefilesarekeptinhere-maycontainsub-folders)||||___native_extension.c||___native_extension.h||___extconf.rb||___+lib||||___(Rubysourcecode)||___Rakefile我无法使此设置与mkmf一起正常工作。native_extension/lib中的文件(包含在native_extension.c中)将被完全忽略。

  6. 安卓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,打开命令窗口,并将路

  7. ruby-on-rails - 向 Rails 3 添加 Ruby 扩展方法的最佳实践? - 2

    我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion

  8. ruby - 允许主机名包含下划线的 URI.parse 的替代方法 - 2

    我正在使用DMOZ的listofurltopics,其中包含一些具有包含下划线的主机名的url。例如:608609TheOuterHeaven610InformationandimagegalleryofMcFarlane'sactionfiguresforTrigun,Akira,TenchiMuyoandotherJapaneseSci-Fianimations.611Top/Arts/Animation/Anime/Collectibles/Models_and_Figures/Action_Figures612虽然此url可以在网络浏览器中使用(或者至少在我的浏览器中可以使用:

  9. ruby - 如何在 ruby​​ 中复制目录结构,不包括某些文件扩展名 - 2

    我想编写一个ruby​​脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"

  10. ruby - 扩展类和实例 - 2

    这个问题有两个部分。在RubyProgrammingLanguage一书中,有一个使用模块扩展字符串对象和类的示例(第8.1.1节)。第一个问题。为什么如果您使用新方法扩展类,然后创建该类的对象/实例,则无法访问该方法?irb(main):001:0>moduleGreeter;defciao;"Ciao!";end;end=>nilirb(main):002:0>String.extend(Greeter)=>Stringirb(main):003:0>String.ciao=>"Ciao!"irb(main):004:0>x="foobar"=>"foobar"irb(main):

随机推荐