概述
继续构建Miwok应用,上次已经成功在四个页面显示了 每个词汇的 两个语言版本
接下来将在每个列表项中为 词汇添加图片 ,最后,对页面进行一下美化,即 将每个页面中列表项的背景色改为 该页面的主题色
目标
- 图片资源添加
- 页面外观改善(列表项的背景色等)
最终的效果,是这样(Phrases 页面不需要添加图片,因为没有合适的图片来表达短语):
实现步骤
更改布局
修改列表项的布局,预留一个应用显示词汇图片的区域:
最终的列表项布局分为左右两部分,左边为该词汇的图片,右边则显示词汇的 Miwok 和 English 语言版本。
而右边的显示词汇部分,又可以分为上下两部分:上面是Miwok版本、下面是English版本。
因此可以考虑使用一个水平的线性布局,再嵌套一个垂直的线性布局来实现:
添加图片资源
首先,将所有的图片文件 放到 资源目录下 的 drawable 文件夹当中,这里就不再截图了。
每个单词都有一个对应的图片( Phrases 页面没有),那么将图片资源的id 封装的每个 Word对象当中是一个可行的策略。
这样 就可以根据每个 Word对象的 图片资源 id 来这 列表项中的图片了。
更改 Word
类如下:为其添加一个成员变量来记录图片资源的id ,以及该成员变量的 Getter
方法:
public class Word {
// …………
/**
* Image resource is for the word
*/
private int imageResourceId = NO_IMAGE_PROVIDED;
/**
* Constant value that represents no image was provided for this word
*/
private static final int NO_IMAGE_PROVIDED = -1;
/**
* Create a new Word object.
*
* @param defaultTranslation is the word in a language that the user is already familiar with
* (such as English)
* @param miwokTranslation is the word in the Miwok language
*/
public Word(String defaultTranslation, String miwokTranslation) {
this.defaultTranslation = defaultTranslation;
this.miwokTranslation = miwokTranslation;
}
/**
* Create a new Word object.
*
* @param defaultTranslation is the word in a language that the user is already familiar with
* (such as English)
* @param miwokTranslation is the word in the Miwok language
* @param imageResourceId is the drawable resource ID for the image associated with the word
* @param audioResourceId is the audio resource id with the word
*/
public Word(String defaultTranslation, String miwokTranslation, int imageResourceId) {
this.defaultTranslation = defaultTranslation;
this.miwokTranslation = miwokTranslation;
this.imageResourceId = imageResourceId;
}
/**
* Get the image resource is for the word
*/
public int getImageResourceId() {
return imageResourceId;
}
/**
* Returns whether or not there is an image for this word.
*/
public boolean hasImage() {
return imageResourceId != NO_IMAGE_PROVIDED;
}
}
- 9 行,添加一个 int 类型 的成员变量,用于存储每个单词 的 图片资源ID,默认初始化为 常量
NO_IMAGE_PROVIDED
- 14 行,常量
NO_IMAGE_PROVIDED
,图片资源id的默认值-1
,用于表示没有图片 - 23 ~ 26 行,原有的构造函数,接受 Miwok 和 English 的字符串参数
- 37 ~ 41 行,新增的构造函数,将 图片资源id 加入到 Word 类的构造函数当中
- 46 ~ 48 行,图片资源id 的 Getter 方法
- 53 ~ 55 行,新增一个方法,用于判断该词汇有无图片资源需要被显示。
这里有两个构造函数,一个接收 图片资源id,而另一个不接收,因为 Phrases 页面不需要显示图片,而 其他几个页面需要显示图片。
现在 , 当我们创建一个 Word 对象时,即可传入该词汇的 图片id。
将每个页面的 onCreate 方法中 构建的数据来源 (ArrayList 对象),加入每个词汇 的 图片资源id:
比如在 NumbersActivity.java
文件的 onCreate
方法中为每个 Word 对象 传入 图片资源id:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_numbers);
setContentView(R.layout.word_list);
// Create a array list of words
ArrayList<Word> words = new ArrayList<Word>();
words.add(new Word("one", "lutti",
R.drawable.number_one, R.raw.number_one));
words.add(new Word("two", "otiiko",
R.drawable.number_two, R.raw.number_two));
words.add(new Word("three", "tolookosu",
R.drawable.number_three, R.raw.number_three));
words.add(new Word("four", "oyyisa",
R.drawable.number_four, R.raw.number_four));
words.add(new Word("five", "massokka",
R.drawable.number_five, R.raw.number_five));
words.add(new Word("six", "temmokka",
R.drawable.number_six, R.raw.number_six));
words.add(new Word("seven", "kenekaku",
R.drawable.number_seven, R.raw.number_seven));
words.add(new Word("eight", "kawinta",
R.drawable.number_eight, R.raw.number_eight));
words.add(new Word("nine", "wo’e",
R.drawable.number_nine, R.raw.number_nine));
words.add(new Word("ten", "na’aacha",
R.drawable.number_ten, R.raw.number_ten));
// …………
}
修改适配器
现在数据来源的 每个 Word 对象当中已经有各自的图片资源id ,接下来就需要 让我们适配器通过其图片资源id 先对应的图片到列表项当中。
因此 在适配器 WordAdapter
的 getView
方法中添加以下代码:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// …………
// Find the ImageView in the list_item.xml layout with the ID image.
ImageView imageView = (ImageView) itemView.findViewById(R.id.image);
// Check if an image is provided for this word or not
if (currentWord.hasImage()) {
// If an image is available, display the provided image based on the resource ID
imageView.setImageResource(currentWord.getImageResourceId());
// Make sure the view is visible
imageView.setVisibility(View.VISIBLE);
} else {
// Otherwise hide the ImageView (set visibility to GONE)
imageView.setVisibility(View.GONE);
}
return itemView;
}
- 7 行,获取用于显示图片的 视图对象
- 9 行,判断 当前的词汇是否需要显示图片。
- 11 ~ 13 行,获取要显示的图片资源id,并将其显示到对应的视图对象当中
- 14 ~ 17 行,不需要显示图片,则将预留的图片显示区域隐藏起来(针对Phrases页面)
列表项图片的添加基本完成,并且在 9 ~ 17 行的 if-else
语句中通过判断是否有图片资源,来显示或隐藏显示图片的视图区域,这样就使得 Phrase 页面 和 其他页面 都能显示正确的内容。
列表项背景色
每个页面的列表项都有不同的背景颜色,而每个页面的列表项都是由单独 的适配器所控制,因此,可考虑将每个页面的背景色id 封装到 各自的 适配器当中,这样每个页面的适配器就可以根据各自的背景色id 来实现 每个页面各自的背景色。
因此 在适配器 WordAdapter
的 getView
方法中添加以下代码:
public class WordAdapter extends ArrayAdapter<Word> {
/**
* Resource ID for the background color for this list of words
*/
private int colorResourceId;
/**
* This is our own custom constructor (it doesn't mirror a superclass constructor).
* The context is used to inflate the layout file, and the list is the data we want
* to populate into the lists.
*
* @param context The current context. Used to inflate the layout file.
* @param words A List of Word objects to display in a list
*/
public WordAdapter(Activity context, ArrayList<Word> words, int colorResourceId) {
// Here, we initialize the ArrayAdapter's internal storage for the context and the list.
// the second argument is used when the ArrayAdapter is populating a single TextView.
// Because this is a custom adapter for two TextViews and an ImageView, the adapter is not
// going to use this second argument, so it can be any value. Here, we used 0.
super(context, 0, words);
this.colorResourceId = colorResourceId;
}
/**
* Provides a view for an AdapterView (ListView, GridView, etc.)
*
* @param position The position in the list of data that should be displayed in the
* list item view.
* @param convertView The recycled view to populate.
* @param parent The parent ViewGroup that is used for inflation.
* @return The View for the position in the AdapterView.
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// ………………
// Set the theme color for the list item
View textContainer = itemView.findViewById(R.id.text_container);
// Find the color that the resource ID maps to
int color = ContextCompat.getColor(getContext(), colorResourceId);
// Set the background color of the text container View
textContainer.setBackgroundColor(color);
// Return the whole list item layout (containing 2 TextViews)
// so that it can be shown in the ListView
return itemView;
}
}
- 6 行,定义一个成员变量,用过存储每个页面 列表项背景色的 id
- 16 ~ 23 行,修改构造函数,传入 每个页面 列表项背景色的 id 值
- 40 行,获取用于设置背景色的视图对象,即列表项右边部分用于显示词汇的区域
- 42 ~ 44 行,获取页面的 列表项背景色的id值,并显示到对应的区域。
至此,每个页面的列表项图片显示,与页面主题也就全部完成了。
最终完成效果也和,预想的一样:
总结
这次的学习并没有太多的新知识,更多的是 遇到问题后应该如何去解决它。
并且当我们在更改一个应用时,或许需要同时改动多个文件,这期间会出现各种各样的错误。
因此,可以尝试 先做应用中 风险最大的更改,这样,如果初始策略行不通,我们将能够及时的 更改策略。
参考
Using an ArrayAdapter with ListView
Performance Tips for Android’s ListView
关于如何为你的类提供构造函数的文档