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 数据库。
但是对于我来说,这个答案中的代码太多了:/
希望这对某人有所帮助。
我对 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 数据库。
但是对于我来说,这个答案中的代码太多了:/
希望这对某人有所帮助。