【问题标题】:Android Listview ArrayAdapter with two layouts具有两种布局的 Android Listview ArrayAdapter
【发布时间】:2015-04-18 19:22:54
【问题描述】:

我对 Android 还是很陌生。在下面的类中,从数据库中检索数据并显示在具有两种不同布局的 ListView 中。 虽然它按预期工作,但问题是滚动不流畅,因为文本视图被一次又一次地分配。我不知道如何只分配一次。请有人帮我解决这个问题。 提前致谢。 我为代码道歉,我知道它看起来很糟糕。

public class FragmentVerses extends ListFragment {

Typeface font;
ViewHolder viewHolder = new ViewHolder();
ViewHolderHeader viewHolderHeader = new ViewHolderHeader();
DatabaseHelper db;

public List<VersesModel> verses;
public List<ChapterModel> chapterName;
ArrayAdapter<VersesModel> adapter;

public FragmentVerses() {
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.verses_fragment, container, false);

    db = new DatabaseHelper(getActivity());
    try {
        db.createDatabase();
    } catch (IOException e) {
        Toast.makeText(getActivity(), "Error Creating Database", Toast.LENGTH_LONG)
                .show();
    }

    verses = db.getVerses(" WHERE " + getActivity().getIntent().getStringExtra(MainActivity.CONDITION));
    chapterName = db.getChapter();
    adapter = new MyListAdapter();
    setListAdapter(adapter);
    return view;
}

private class MyListAdapter extends ArrayAdapter<VersesModel> {
    public MyListAdapter() {
        super(getActivity(), R.layout.verses_custom_list, verses);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        VersesModel currentVerse = verses.get(position);
        if (convertView == null) {
            convertView = getActivity().getLayoutInflater().inflate(
                    R.layout.verses_custom_list, parent, false);
            font = Typeface.createFromAsset(convertView.getContext().getAssets(), "Quran_Taha.ttf");
            viewHolder.textView = (TextViewEx) convertView.findViewById(R.id.textView_Verse);
            viewHolder.textViewTranslation = (TextView) convertView.findViewById(R.id.textView_VerseTranslation);
            viewHolder.nView = (TextView) convertView.findViewById(R.id.textView_verseNumber);
            viewHolder.textView.setTypeface(font);
            viewHolder.imageView = (ImageView) convertView.findViewById(R.id.versesImageView);
            convertView.setTag(viewHolder);
        } else {
            if (currentVerse.getVerseNumber() != 0) {
                convertView = getActivity().getLayoutInflater().inflate(
                        R.layout.verses_custom_list, parent, false);
                viewHolder.textView = (TextViewEx) convertView.findViewById(R.id.textView_Verse);
                viewHolder.nView = (TextView) convertView.findViewById(R.id.textView_verseNumber);
                viewHolder.textViewTranslation = (TextView) convertView.findViewById(R.id.textView_VerseTranslation);
                viewHolder.textView.setTypeface(font);
                viewHolder.textView.setText(currentVerse.getVerseText() + "", true);
                viewHolder.textViewTranslation.setText(currentVerse.getVerseTranslation());
                viewHolder.nView.setText(currentVerse.getVerseNumber() + "");
                convertView.setTag(viewHolder);
            } else {
                convertView = getActivity().getLayoutInflater().inflate(
                        R.layout.verses_custom_list_header, parent, false);
                ChapterModel chapterModel = chapterName.get(currentVerse.getChapterNumber() - 1);
                if (viewHolderHeader.textViewChapter == null)    viewHolderHeader.textViewBismillah = (TextView) convertView.findViewById(R.id.textView_Verse_Bismillah);
                    viewHolderHeader.textViewChapter = (TextView) convertView.findViewById(R.id.textView_Verse_ChapterName);
                    viewHolderHeader.textViewChapter.setText("سورة  " + chapterModel.getChapterText());
                    viewHolderHeader.textViewBismillah.setTypeface(font);
                    viewHolderHeader.textViewChapter.setTypeface(font);
                } else {
                    viewHolderHeader = (ViewHolderHeader) convertView.getTag();
                }
                convertView.setTag(viewHolderHeader);

            }
        }
        return convertView;
    }
}

【问题讨论】:

  • 你为什么要夸大视图这么多次。您只需充气一次,系统会在需要时回收视图。这就是您的列表如此缓慢的原因。查找使用 ArrayAdapters 创建列表视图。

标签: android listview android-arrayadapter


【解决方案1】:

我知道这篇文章很旧,但仅供将来参考... 在这种情况下,您应该使用 ViewHolder 模式。

如果您想使用 2 个布局,只需创建两个 ViewHolder 并在 getView 方法中切换。

与公认的答案非常相似,但性能更好。

声明视图类型。

private final int VIEW_TYPE_EXAMPLE = 0;
private final int VIEW_TYPE_EXAMPLE_TWO = 1;

返回与您在上面声明的一样多的类型。

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

当 item 位于位置 X 时返回 viewType 时切换。在这种情况下,我只在 item 是列表中的第一个时更改类型。

@Override
public int getItemViewType(int position) {
    return (position == 0) ? VIEW_TYPE_EXAMPLE : VIEW_TYPE_EXAMPLE_TWO;
}

创建与您的布局相匹配的视图持有者。他们将保存您的数据。

class SecondViewHolder {
            TextView mDate;
            TextView mDescription;
            TextView mObservations;

            public SecondViewHolder(View view) {
                mDate = (TextView) view.findViewById(R.id.txt_date);
                mDescription = (TextView) view.findViewById(R.id.txt_description);
                mObservations = (TextView) view.findViewById(R.id.txt_observations);
            }
        }

class FirstViewHolder {
            ImageView mPhoto;
            TextView mName;
            TextView mAge;

            public FirstViewHolder(View view) {
                mPatientPhoto = (ImageView)view.findViewById(R.id.img_photo);
                mPatientName = (TextView)view.findViewById(R.id.txt_name);
                mPatientAge = (TextView)view.findViewById(R.id.txt_age);
            }
        }

在 getView 方法中在 then 之间切换。

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

            int viewType = getItemViewType(position);

            switch (viewType) {

                case VIEW_TYPE_EXAMPLE: {
                    FirstViewHolder firstViewHolder = null;

                    if(convertView == null){
                        convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_example, parent, false);
                        firstViewHolder = new FirstViewHolder(convertView);
                        convertView.setTag(firstViewHolder);
                    }
                    else firstViewHolder = (FirstViewHolder)convertView.getTag();

                    firstViewHolder.mName.setText("Your name");
                    firstViewHolder.mAge.setText("20 years old");

                    break;
                }

                case VIEW_TYPE_EXAMPLE_TWO: {
                    SecondViewHolder holder = null;

                    if(convertView == null){
                        convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_example_two, parent, false);
                        holder = new SecondViewHolder(convertView);
                        convertView.setTag(holder);
                    }
                    else holder = (SecondViewHolder)convertView.getTag();

                    holder.mDate.setText("01/01/2016");
                    holder.mDescription.setText("Description");
                    holder.mObservations.setText("Obs");


                    break;
                }
            }

            return convertView;
        }

但我不能忽视这样一个事实,即在这个特定问题中,您应该使用 CursorAdapter,因为您是从数据库中查询的。

您也不应该直接访问数据库。 应该创建一个 Loader(执行异步任务但不绑定到活动)。

如果您想遵循最佳实践并在以后省去一些麻烦,请创建 ContentProvider 来管理您的 SQLite 数据库。

但是对于我来说,这个答案的代码太多了:/

希望这对某人有所帮助。

【讨论】:

    【解决方案2】:

    Android 的适配器提供了一种在单个适配器中使用多个布局的方法。

    首先,告诉你的适配器你需要多少个布局:

    public int getViewTypeCount()
    {
        return 2;
    }
    

    然后,给出一些逻辑来判断当前项应该使用哪种布局:

    public int getItemViewType(int position)
    {
        if (verses.get(position).getVerseNumber() != 0)
        {
            return 0;
        }
    
        return 1;
    }
    

    最后,在您的构建中适当的视图:

    public View getView(int position, View convertView, ViewGroup parent)
    {
        if (this.getItemViewType(position) == 0)
        {
            // TODO Build the appropriate view
            return view;
        }
    
        // TODO Build the appropriate other view
        return view;
    }
    

    【讨论】:

    • 感谢@Gaetan,稍加修改它对我有用。虽然我还是觉得有点落后。
    【解决方案3】:

    有两点需要修改看看下面的代码,它会给你一些想法。您不必每次都膨胀布局,也无需每次都调用 findViewById 以及查看下面的示例代码

        ViewHolder holder;
        if ((convertView == null)) {
            convertView = layoutInflater
                    .inflate(R.layout.list_item,
                            viewGroup, false);
            holder = new ViewHolder();
            holder.itemImage = (ImageView) convertView
                    .findViewById(R.id.logo);
            holder.itemName = ((TextView) convertView
                    .findViewById(R.id.title_product_search));
            convertView.setTag(holder);
    
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        //assign text and images to controls after this
        holder.itemName.setText("text");
        imageLoader.displayImage(item.imageUrl, holder.itemImage,
                    options);
    

    【讨论】:

      【解决方案4】:

      这就是我所做的。

      private class MyListAdapter extends ArrayAdapter<VersesModel> {
          public MyListAdapter() {
              super(getActivity(), R.layout.verses_custom_list, verses);
          }
      
          @Override
          public int getViewTypeCount() {
              return 2;
          }
      
          @Override
          public int getItemViewType(int position) {
              if (verses.get(position).getVerseNumber() != 0) {
                  return 0;
              }
              return 1;
          }
      
          @Override
          public View getView(int position, View convertView, ViewGroup parent) {
              VersesModel currentVerse = verses.get(position);
      
      
              if (convertView == null) {
                  viewHolder = new ViewHolder();
                  switch (getItemViewType(position)) {
                      case 0:
                          convertView = getActivity().getLayoutInflater().inflate(
                                  R.layout.verses_custom_list, parent, false);
                          viewHolder.textView = (TextViewEx) convertView.findViewById(R.id.textView_Verse);
                          viewHolder.nView = (TextView) convertView.findViewById(R.id.textView_verseNumber);
                          viewHolder.textViewTranslation = (TextView) convertView.findViewById(R.id.textView_VerseTranslation);
                          font = Typeface.createFromAsset(convertView.getContext().getAssets(), "Quran_Taha.ttf");
                          viewHolder.textView.setTypeface(font);
                          Toast.makeText(getActivity(), "" + position, Toast.LENGTH_SHORT).show();
                          break;
                      case 1:
                          convertView = getActivity().getLayoutInflater().inflate(
                                  R.layout.verses_custom_list_header, parent, false);
                          chapterModel = chapterName.get(currentVerse.getChapterNumber() - 1);
                          viewHolder.textView = (TextViewEx) convertView.findViewById(R.id.textView_Verse_Bismillah);
                          viewHolder.nView = (TextView) convertView.findViewById(R.id.textView_Verse_ChapterName);
                          font = Typeface.createFromAsset(convertView.getContext().getAssets(), "Quran_Taha.ttf");
                          viewHolder.textView.setTypeface(font);
                          viewHolder.nView.setTypeface(font);
                          break;
                  }
                  convertView.setTag(viewHolder);
              } else {
                  viewHolder = (ViewHolder) convertView.getTag();
              }
              switch (getItemViewType(position)) {
                  case 0:
                      viewHolder.textView.setText(currentVerse.getVerseText() + "", true);
                      viewHolder.textViewTranslation.setText(currentVerse.getVerseTranslation());
                      viewHolder.nView.setText(currentVerse.getVerseNumber() + "");
                      break;
                  case 1:
                      viewHolder.nView.setText("سورة  " + chapterModel.getChapterText());
                      break;
              }
              return convertView;
          }
      }
      

      当列表加载时,toast 显示 3 次,并且开始时滚动速度较慢。

      【讨论】:

      • 您正在为每个视图和每个视图类型执行此操作:font = Typeface.createFromAsset(convertView.getContext().getAssets(), "Quran_Taha.ttf");。也许您只能在适配器构造函数中加载一次。不确定它是否会改变您的速度问题。
      猜你喜欢
      • 2015-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-19
      • 2012-07-02
      • 2013-11-12
      • 2011-06-14
      相关资源
      最近更新 更多