本文是我们名为“ Android UI设计–基础 ”的学院课程的一部分。
在本课程中,您将了解Android UI设计的基础知识。 您将了解用户输入,视图和布局以及适配器和片段。 在这里查看 !
目录
1.概述
在上一篇文章中 ,我们介绍了有关Android UI模式的一些基本概念,并了解了如何按照这些模式创建一致的UI。 在本文中,我们希望探索有关Views
更多信息,以及如何使用Views
构建出色的用户界面。 本文将介绍有关“ Views
和Adapters
概念。 在Android中开发用户界面非常简单,因为我们可以使用XML文件对其进行描述,并且系统将进行繁重的工作以将其转换为实际的用户界面组件,并根据屏幕尺寸和分辨率进行放置。
Android UI框架提供了一些基本的UI组件,称为控件或小部件,可帮助开发人员编码和构建应用程序。
2.意见
View
类是所有组件扩展的基本类。 View
在一块屏幕上绘制一些东西,它负责在用户与其交互时处理事件。 甚至通用的ViewGroup
类也扩展了View
。 ViewGroup
是一个特殊的View
,它包含其他视图并按照某些规则放置这些视图。 我们将看到Android提供了一些专门的视图,这些视图可以帮助我们处理文本,图像,用户输入,按钮等。
所有这些视图都有一些共同的关键方面:
- 所有视图都有一组属性:这些属性会影响视图的呈现方式。 所有视图共有一组属性,而其他一些属性则取决于视图的类型。
- 焦点:系统管理每个视图上的焦点,并根据用户输入,我们可以修改焦点并将焦点强制到特定视图。
- 侦听器:所有视图都有侦听器,这些侦听器用于在用户与视图进行交互时处理事件。 我们可以注册我们的应用以侦听视图中发生的特定事件。
- 可见性:我们可以控制视图是否可见,也可以在运行时更改视图的可见性。
视图属性是一个键值对,可用于自定义视图行为。 属性值可以是:
- 一个号码
- 一个字符串
- 对写在别处的值的引用
前两个选项很简单,第三个选项最有趣,因为我们可以创建一个保存值列表的文件(总是XML格式),并且可以在属性值中引用它。 这是最好的遵循方法,尤其是当我们使用主题和样式或我们想要支持多语言应用程序时。
最重要的属性之一是视图ID :这是视图的唯一标识符,我们可以使用此ID查找特定的视图。 这是一个“静态”属性,表示一旦定义便无法更改。
当我们想要设置一个view属性时,我们有两种方法可以做到:
- 在定义视图时使用XML
- 以编程方式
例如,假设我们要定义一个TextView
(它写一个文本)。 在XML中,我们有:
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
正如您所注意到的,我们定义了一个名为textView1的id ,其他一些属性具有字符串值,而另一个属性android:text引用了写在其他地方的值。
我们可以只使用代码行来做同样的事情:
TextView tv = new TextView(this);
tv.setText("blabla");
这两种方法是等效的。 但是,首选XML。 XML视图属性和Java方法之间存在对应关系:通常对于每个XML属性,都有一个可在代码中使用的set方法。 您可以在此处查看有关此通信的更多信息。 在XML中,视图属性称为属性。
发挥重要作用的两个属性是layout_width
和layout_height
。 这两个属性定义视图的大小和高度。 我们可以使用两个预定义的值:
-
MATCH_PARENT
-
WRAP_CONTENT
对于MATCH_PARENT
值,我们的意思是我们希望它的视图和容纳它的父视图一样大,而对于WRAP_CONTENT
我们指定视图必须足够大才能容纳它的内容。
还有另一种选择:使用数字值。 在这种情况下,我们指定视图的确切度量。 在这种情况下,最佳实践建议使用dp单位测量,以便我们的视图可以适应不同的屏幕密度。
谈到视图侦听器,当我们希望收到某些事件的通知时,这是一种众所周知的方法。 Java中的侦听器是定义一些方法的接口,我们的侦听器类必须实现这些方法,以便在发生特定事件时可以接收通知。
Android SDK具有多种侦听器类型,因此可以实现不同的接口。 最受欢迎的两个是: View.OnClickListener
, View.OnTouchListener
等等。
Android提供了几个标准组件,当然,如果我们找不到满足我们需求的组件,则可以随时实现自定义视图。 使用自定义视图,我们可以定义视图将在屏幕上绘制的内容及其行为。 我们甚至可以定义影响视图行为的自定义属性。 在这种情况下,我们必须扩展基本的View
类并重写某些方法。
TextView组件
这是最简单的组件之一。 当我们想在屏幕上显示文本时使用它。 我们之前看过它:
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
android:text
包含我们要显示的文本。 它具有一些属性,可用于指定我们如何显示文本:
-
android:fontFamily
–它是字体家族。 -
android:shadowColor
–这是阴影颜色。 -
android:shadowDx
–它是阴影x轴的偏移量。 -
android:shadowDy
–它是阴影y轴的偏移量。 -
android:textStyle
–它是样式(粗体,斜体,粗体)。 -
android:textSize
–它是文本大小。
以下是TextView
一些示例:
相应的XML为:
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android UI" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android UI"
android:textStyle="italic" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android UI"
android:textColor="#FFFFFF"
android:textSize="15dp"
android:textStyle="bold" />
ImageView组件
此组件用于在屏幕上显示图像。 我们想要显示的图像可以放置在我们的apk内 ,也可以远程加载。 在第一种情况下,我们的图像必须放置在res/drawable
目录下。 基于我们在上一篇文章中讨论的内容 ,我们已经知道必须记住我们的应用程序可以在具有不同屏幕密度的多设备上运行。
为了更好地支持不同的屏幕密度,我们可以创建具有不同分辨率的不同图像。 res/drawable
目录是系统找不到默认密度的图像时,系统在其中查找的默认目录。 一般而言,我们必须创建至少四个具有不同分辨率的不同图像,实际上我们可以在IDE中注意到至少有五个目录:
-
drawable-ldpi
(不再受支持) -
drawable-mdpi
(中dpi) -
drawable-hdpi
(高dpi) -
drawable-xhdpi
(超高dpi) -
drawable-xxhdpi
(x特高dpi) -
drawable
要记住的重要一点是:图像必须具有相同的名称。 一旦有了它,我们可以通过以下方式使用ImageView
:
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/robot" />
我们使用@drawable/robot
(不带扩展名)引用了名为robot.png的图像。 结果如下所示:
如果必须远程加载映像,则在执行操作时要记住一些注意事项。 首先,您应该考虑从远程服务器加载图像是一项耗时的操作,并且应该在单独的线程中进行操作,这样才能避免ANR(应用程序无响应)问题。 如果您想使事情简单,则可以使用AsyncTask
或Volley lib。 要记住的第二件事是您不能在XML文件中设置图像,但是只能定义ImageView
而不必引用图像。 在这种情况下,您可以使用以下方法设置图像:
img.setImageBitmap(your_bitmap)
其中your_bitmap是您已远程加载的图像。
输入控件
Input controls
是用户可以与之交互的组件。 使用这样的组件,例如,您可以让用户有机会插入一些值。 Android UI框架提供了广泛的输入控件: text field
, input field
, toggle buttons
, radio buttons
, buttons
, checkbox
, pickers
等。 它们每个都有一个专门的类,我们可以使用这些组件来构建复杂的接口。
下面列出了一些通用组件,以及处理该组件的类:
我们希望将注意力集中在Android UI中广泛使用的Button
组件上。 首先,我们必须使用XML文件定义UI:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="@+id/Btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click here!" />
</RelativeLayout>
请注意,在按钮ID中,我们使用了@+id
这意味着我们要添加一个新的ID,而android:text
属性是我们要在按钮上显示的字符串。 您可以使用参考代替直接编写文本。 如果我们使用此布局创建一个简单的应用程序并运行它,我们将拥有:
稍后我们将看到如何捕获UI事件,以便处理用户点击。 我们可以考虑更复杂的接口:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="@+id/Btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click here!" />
<CheckBox
android:id="@+id/checkBox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/Btn"
android:layout_below="@+id/Btn"
android:layout_marginTop="29dp"
android:text="CheckBox" />
<ToggleButton
android:id="@+id/toggleButton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/checkBox1"
android:layout_below="@+id/checkBox1"
android:layout_marginTop="20dp"
android:text="ToggleButton" />
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/toggleButton1"
android:layout_centerVertical="true"
android:ems="10"
android:hint="Your name here" >
<requestFocus />
</EditText>
<Switch
android:id="@+id/switch1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/toggleButton1"
android:layout_alignBottom="@+id/toggleButton1"
android:layout_alignParentRight="true"
android:text="Switch" />
<RadioGroup
android:id="@+id/radioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/editText1"
android:layout_below="@+id/editText1"
android:layout_marginTop="24dp" >
<RadioButton
android:id="@+id/radioButton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/editText1"
android:layout_below="@+id/editText1"
android:layout_marginTop="40dp"
android:text="Option 1" />
<RadioButton
android:id="@+id/radioButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/radioButton1"
android:layout_below="@+id/radioButton1"
android:text="Option 2" />
</RadioGroup>
</RelativeLayout>
在此界面中,我们几乎使用了所有UI组件,如果运行该应用程序,我们将:
3. UI事件和监听器
到目前为止,我们已经创建了Android用户界面,但尚未考虑如何处理用户与我们的应用进行交互时所生成的事件。
Listeners
是在Android中开发UI时的重要方面。 一般而言,当用户与我们的应用程序界面交互时,系统会“创建”一些事件。 构建我们的界面的每个视图都能够生成事件并提供处理事件的方法。
从API的角度来看,如果我们View
类,我们会注意到有一些公共方法。 发生某些事件时,系统将调用这些方法。 它们被称为callback
方法,它们是我们捕获用户与我们的应用程序交互时发生的事件的方式。 通常,这些回调方法以on + event_name
开头。
每个View
提供了一组回调方法。 一些视图在多个视图之间是通用的,而另一些则是特定于视图的。 无论如何,为了使用这种方法,如果我们想捕获一个事件,我们应该扩展View
,这显然是不切实际的。 因此,每个View
都有一组接口,我们必须实现这些接口,以便收到有关发生的事件的通知。 这些接口提供了一组回调方法。 我们称这些接口为事件监听器。 因此,例如,如果我们希望在用户单击按钮时得到通知,我们有一个名为View.onClickListener
的接口来实现。
让我们考虑上面的示例,当我们在UI中使用Button
时。 如果我们想添加一个侦听器,我们要做的第一件事就是获取对Button
的引用:
Button b = (Button) findViewById(R.id.btn);
在我们的Activity
有一个名为findViewById
的方法,该方法可用于获取对在我们的用户界面中定义的View
的引用。 获得参考后,我们可以处理用户单击:
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// here we handle the event
}
});
如您所见,我们使用了一种紧凑形式,您会注意到称为onClick
的回调方法。 当用户单击我们的按钮时,系统会调用此方法,因此在这里我们必须处理事件。 我们可以通过不同的方式获得相同的结果:我们可以使Activity
实现View.OnClickListener
接口并再次实现onClick
。 结果是运行我们拥有的应用程序:
如果我们想听不同的事件,我们可以使用相同的技术。
4. UI开发
之前,我们简短介绍了“ Activity
概念。 现在是时候更好地解释其功能了。 如果没有用于容纳它的容器,那么Android UI将不存在。 这个容器称为Activity
,它是Android中最重要的概念之一。 我们将创建的每个应用程序都至少具有一个Activity
,通常,更复杂的应用程序具有多个活动,这些活动可以相互交互以使用Intents
交换数据和信息。 一个Activity
负责创建一个放置UI的窗口。
现在,我们可以构建一个使用上面显示的UI组件并将其混合的完整应用程序。 假设我们要创建一个询问用户名的应用程序,并且该应用程序有一个按钮来确认它。
第一件事是创建一个布局。 我们假设您已经知道如何创建Android项目。 如果不是,请参阅我们的“ Android Hello World”文章 。 在Android中(即使用Eclipse作为IDE),我们必须将XML文件放在res/layout
。 如果仔细看,您会发现存在具有不同名称和扩展名的不同子目录。 到目前为止,将文件添加到res/layout
(默认目录)下就足够了。 根据设备的类型,将使用其他目录,以便我们有机会根据屏幕尺寸和方向来优化UI。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/edt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Please insert your username" />
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView1"
android:layout_below="@+id/textView1"
android:ems="10" />
<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="16dp"
android:text="Confirm" />
</RelativeLayout>
activity_main.xml
接下来,我们必须创建一个活动。 如果使用IDE,我们会注意到它已经创建了一个默认类(在Eclipse中,它称为MainActivity.java
)。 查看其源代码,有一个onCreate
方法。 在这里,我们要做的第一件事是将UI“附加”到活动:
setContentView(R.layout.activity_main);
接下来,我们可以处理click事件:当用户单击时,我们可以检索EditText
值并显示一条消息:
// Lookup Button reference
Button b = (Button) findViewById(R.id.btn1);
// Lookup EditText reference
final EditText edt = (EditText) findViewById(R.id.editText1);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String txt = edt.getText().toString();
Toast.makeText(MainActivity.this, "Hello " + txt, Toast.LENGTH_LONG).show();
}
});
运行我们获得的应用程序:
这是一个非常简单的示例,但是了解如何创建用户界面很有用。
5.视图和适配器
到目前为止,我们讨论了仅显示一个值的UI组件。 某些组件可以显示多个值或数据集合。 这种控件称为List
控件。 如果要在Android中使用这些控件,则不能像以前那样使用单个组件,而必须使用两个组件:一个用于管理数据的显示方式,另一个用于管理基础数据。 最后一个称为Adapter
。 列表控件扩展了AdapterView
,最“著名”的列表控件是:
- 列表显示
- 微调器
- 网格视图
- 画廊
ListView
组件在列表中显示其项目。 这在Android UI中经常使用。
Spinner
是另一个组件,它仅显示一个项目,但让用户在多个项目中进行选择。
GridView
以表格形式显示其子级,表格是可滚动的,我们可以设置要显示的列数。
Gallery
以水平滚动方式显示项目。 自API级别16开始不推荐使用此组件。我们将重点放在前两个组件上,因为它们在构建用户界面时非常有用。
看一下API, AdapterView
扩展了ViewGroup
因此它们都间接扩展了View
类。 扩展ViewGroup
意味着列表控件将视图列表作为子级保存,同时它也是一个View
。 适配器的作用是管理数据,并根据必须显示的数据提供适当的子视图。 Android提供了一些通用适配器。 数据可以从数据库,资源中加载,也可以动态创建。
让我们假设我们要创建一个显示项目列表的用户界面。 让我们假设项目只是字符串。 在这种情况下,我们要做的第一件事就是创建一个ArrayAdapter
。 这是最常用的适配器之一,因为它们非常易于使用。 我们可以为孩子使用预先构建的布局,这样我们就不必工作太多。 Android提供了几种可供使用的预构建布局。
我们的XML应用UI如下所示:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
现在我们必须创建适配器,以便显示项目:
ArrayAdapter<String> aAdpt = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
new String[]{"Froyo", "Gingerbread", "Honeycomb", "Ice cream Sandwich", "Jelly Bean", "KitKat"});
这样,我们使用android.R.layout.simple_list_item_1
(由Android提供的布局)作为子布局创建了一个ArrayAdapter
,并创建了一个字符串列表作为数据。 现在,我们必须将适配器添加到列表视图:
ListView lv = (ListView) findViewById(R.id.list);
lv.setAdapter(aAdpt);
运行该应用程序,我们有:
在上面的示例中,我们将项目提供为直接写在源代码中的字符串列表。 我们可以在资源文件中提供这样的列表。 我们可以假设我们有一个Spinner
组件,该组件的子组件是从资源文件中检索到的。 首先,我们创建ArrayAdapter
:
ArrayAdapter<CharSequence> aAdpt = ArrayAdapter.createFromResource(this, R.array.days, android.R.layout.simple_spinner_item);
其中R.array.days
是我们的数组资源文件(包含日期名称),而android.R.layout.simple_spinner_item
是子级布局。 然后,将适配器连接到微调器:
aAdpt.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(aAdpt);
运行该应用程序,我们有:
在某些情况下,要显示的信息存储在数据库中。 在这种情况下,Android提供了一些专用适配器,可帮助我们从数据库读取数据并填充相应的列表控件。 该适配器称为CursorAdapter
或者,如果我们愿意,可以使用SimpleCursorAdapter
。 例如,当我们要使用存储在智能手机中的联系人填充ListView
时,可以使用这种类型的适配器。 在这种情况下,我们可以使用CursorAdapter
。
处理ListView事件
另一个重要方面是用户和列表组件之间的交互。 我们将注意力集中在ListView
。 可以将相同的注意事项应用于其他类型的列表组件。 通常,当我们在应用程序界面中具有ListView
时,我们想知道用户单击的项目。 与其他UI组件一样,我们可以使用事件侦听器。 如果您回想起有关ListView
的先前示例,则用于处理事件的代码如下:
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> aView, View view, int position,long id) {
// We handle item click event
TextView tv = (TextView) view;
String text = (String) tv.getText();
Toast.makeText(MainActivity.this, "You clicked on " + text, Toast.LENGTH_LONG).show();
}
});
分析上面的代码,我们只需设置一个项目单击侦听器,在这种情况下,我们必须重写一个名为onItemCick
的方法。 在此方法中,我们接收AdapterView
,单击的View
以及ListView
内的位置及其ID作为参数,作为参数。 我们已经知道View
是TextView
因为我们使用了字符串的ArrayAdapter
,所以我们可以安全地将视图转换为文本视图。 一旦知道TextView
单击,我们就可以检索文本。
自定义适配器和视图架模式
在某些情况下,标准适配器不够用,我们希望对子视图有更多的控制,或者想向子视图添加其他组件。 决定实施自定义适配器时,还应考虑其他原因:可能是您有一些数据管理要求,使用自定义适配器无法满足您的要求,或者您想要实施缓存策略。
在所有这些情况下,我们都可以实现自定义适配器:例如,您可以决定扩展BaseAdapter
抽象类,或者可以扩展某些专门的类作为ArrayAdapter
。 选择取决于您必须处理的信息类型。 为了简单起见,将注意力集中在自定义适配器上,我们假设要创建一个ListView,其中子视图具有两个文本行。
首先,我们创建适配器并开始实现一些方法:
public class CustomAdapter extends BaseAdapter {
@Override
public int getCount() {
// TODO Auto-generated method stub
return 0;
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int arg0, View arg1, ViewGroup arg2) {
// TODO Auto-generated method stub
return null;
}
}
我们必须实现四种方法。 在进行此操作之前,我们定义一个作为数据模型的类。 为简单起见,我们可以假设我们有一个名为Item
的类,该类具有两个公共属性: name和descr 。 现在我们需要一个子布局,以便我们可以显示数据:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/descr"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
item_layout.xml
在我们的适配器中,我们需要一个构造函数,以便我们可以传递想要显示的数据:
public CustomAdapter(Context ctx, List<Item> itemList) {
this.ctx = ctx;
this.itemList = itemList;
}
现在,重写方法非常简单,除了getView
之外:
@Override
public int getCount() {
return itemList == null ? 0 : itemList.size();
}
@Override
public Object getItem(int pos) {
return itemList == null ? null : itemList.get(pos);
}
@Override
public long getItemId(int pos) {
return itemList == null ? 0 : itemList.get(pos).hashCode();
}
请注意,在getItemId
我们返回代表该项目的唯一值。 getView
方法稍微复杂一点。 这是定制适配器的核心,我们必须仔细实现它。 每当ListView
必须显示子数据时,都会调用此方法。 在这种方法中,我们可以手动创建视图或为XML文件充气:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater lInf = (LayoutInflater)
ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = lInf.inflate(R.layout.item_layout, null);
}
TextView nameView = (TextView) v.findViewById(R.id.name);
TextView descrView = (TextView) v.findViewById(R.id.descr);
nameView.setText(itemList.get(position).name);
descrView.setText(itemList.get(position).descr);
return v;
}
通过分析代码,我们可以注意到我们首先检查作为参数传递的视图不为null。 这是必要的,因为Android系统可以重用View而不浪费资源。 因此,如果视图不为null,则可以避免膨胀XML布局文件。 如果为null,则必须为布局文件充气。 下一步是在布局内查找TextView
以便我们设置其值。 运行该应用程序,我们将获得:
查看getView
方法,我们可以注意到我们多次调用findViewById
。 这是一项昂贵的操作,我们应该避免在不必要的时候调用它,因为它会降低整体Listview
性能,并且当用户滚动ListView
它可能会发生不稳定。
此外,即使视图被回收,我们也使用findViewById
。 在这种情况下,我们可以应用减少这种方法使用的模式。 这种模式称为View Holder
,它要求我们创建一个对象来保存对我们的子布局内的视图的引用。 应用此模式的getView
方法变为:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
TextHolder th = null;
if (v == null) {
LayoutInflater lInf = (LayoutInflater)
ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = lInf.inflate(R.layout.item_layout, null);
TextView nameView = (TextView) v.findViewById(R.id.name);
TextView descrView = (TextView) v.findViewById(R.id.descr);
th = new TextHolder();
th.nameView = nameView;
th.descrView = descrView;
v.setTag(th);
}
else
th = (TextHolder) v.getTag();
th.nameView.setText(itemList.get(position).name);
th.descrView.setText(itemList.get(position).descr);
return v;
}
static class TextHolder {
TextView nameView;
TextView descrView;
}
6.下载源代码
这是使用Android Views的课程。 您可以在此处下载源代码: AndroidView.zip
翻译自: https://www.javacodegeeks.com/2015/09/android-ui-understanding-views.html