Android 具有两种布局的 Listview ArrayAdapter

Android Listview ArrayAdapter with two layouts

我对 Android 很陌生。在下面的 class 中,数据从数据库中检索并显示在具有两种不同布局的 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;
    }
}

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;
}

有两处需要更改,请查看下面的代码,它会给您一些想法。您不必每次都膨胀布局,也不需要每次都调用 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);

这是我所做的。

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 次,开始时滚动较慢。

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

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

与接受的答案非常相似,但性能更好。

声明视图类型。

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

Return 与上面声明的类型一样多。

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

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

@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(执行异步任务但不绑定到 activity)。

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

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

希望这对某人有所帮助。