片段(Fragment)

一个片段代表了一个Activity的一种行为或是其用户界面的一个区域。可以在一个单独的活动中组合多个分片来组建一个多面板UI,并在不同的活动中多次利用同一个分片。可以把片段理解为一个活动的一个模块化部分,有其自己的生命周期,接收其自己的输入事件,并且可以在活动运行过程中添加或移除一个片段。(译注:网络上也有“碎片”的译法,不过目前还并没有统一的名称。在这里姑且称为“片段”,个人感觉比“碎片”听起来舒服一些 :)  )

一个片段必须被嵌在一个活动中,它的生命周期与该活动的有着紧密联系。例如,当活动被暂停(pause),该活动中所有的片段也会暂停,当活动被销毁(destroy),其中所有的片段也会被销毁。不过,当活动在运行时(处于resumed生命周期状态),可以单独改变每一个片段,如添加或是删除它们。当进行这样的片段处理时,还能将片段加入一个由该活动管理的返回栈——每个活动中的返回栈条目是一段发生过的片段处理的记录。返回栈允许用户通过按下BACK键撤销一个片段事务(反向导航)。

在添加一个片段作为活动布局的一部分时,它将存在于活动的视图层级的ViewGroup中,并定义其自有的视图布局。可以通过在活动布局文件中以<fragment>元素声明片段,或是在程序代码中添加至已有的ViewGroup)来将一个片段插入活动的布局之中。不过,片段并不一定要是活动布局的一部分;还可以将片段作为一个活动的不可见部分使用。

本文档描述了如何使用片段来构建应用程序,包括片段如何在被加入活动的返回栈时维护其状态,与活动及活动内的其他片段共享事件,以及和活动的动作条相结合等。

设计理念

Android在Android 3.0(API级别“Honeycomb”蜂巢)中引入了片段,用以在平板等大屏幕上支持更为动态而灵活的UI设计。由于平板等屏幕比手机的要大许多,因此有更多的空间来交互组合UI组件。片段可以在不必考虑视图层级的复杂操作的情况下实现这种设计。通过把活动的布局分成一个个片段,就可以在运行时改变活动的外观并在该活动所管理的返回栈中保存这些变化。

例如,一个新闻程序可以在左侧用一个片段来展示条目列表,在另一边的片段中显示一条条目——两个片段同时显示在一个活动中的两边,且都有自己的生命周期回馈方法并处理其自有的用户输入事件。因此,相比一个活动选择条目另一个活动阅读条目,现在用户可以在同一个活动中选择条目并阅读,就像图1所示的那样。

图1 一个演示了如何通过片段将两个独立的UI模块并入一个活动的范例

一个片段应该是程序中的一个模块化的可重用的组件。也就是说,因为片段定义了其自有的布局以及使用了自有生命周期回馈方法的自有行为,所以可以将一个片段用在多个活动之中。这是很重要的一点,它使得能够在不同屏幕尺寸上提供不同的用户体验。例如,可以只在屏幕尺寸足够大时才在一个活动中包含多个片段,否则,就将不同片段分在不同的活动中使用。

例如——还是那个新闻程序的例子——程序可以在运行于一个超大屏幕设备(extra large screen,比如平板电脑)时将两个片段嵌入在一个Activity A中。不过,在普通尺寸屏幕的设备(例如,手机)上,就没有足够的空间放下两个片段,所以Activity A仅包含了条目列表功能的片段,而当用户选择了一个条目时,它将启动包含了阅读条目的片段的Activity B。因此,如图1所示程序将同时支持两种设计模式。

创建一个片段

要创建一个片段,必须创建一个Fragment(或它的一个已有的子类)的子类。Fragment类的代码看起来和一个Activity很相似。它包含了和一个活动类似的回馈方法,例如onCreate()、onStart()、onPause()和onStop()。事实上,如果要把一个已有的Android程序改为通过片段来实现,只需简单地把代码中的活动的回馈方法改为相应的片段的回馈方法。

通常,至少需要实现以下的生命周期方法:

onCreate()

系统在创建片段时将调用这个方法。在其实现中,应当初始化那些希望在该片段暂停或停止时被保留的必要组件以供之后继续使用。

onCreateView()

系统在片段第一次绘制其用户界面时将调用这个方法。要绘制片段的UI,就必须从这个方法返回一个片段布局的根View。如果片段不提供UI,可以只返回一个null。

onPause()

系统将调用该方法作为用户将要离开该片段的第一个标志(尽管这不意味着片段一定就会被销毁)。通常应当在这里保存当前用户进行的操作(因为用户之后或许不会返回该片段了)。

大部分的程序应当为每一个片段至少实现以上三个方法,不过还有一些其他的回馈方法可以用来处理片段生命周期的不同阶段。所有的生命周期回馈方法会在之后的“处理片段生命周期”一节再讨论。

图2. 一个片段的生命周期(当其所属的活动处于运行状态时)

除了Fragment基类之外,还有一些可供继承的子类:

DialogFragment

显示一个浮动对话框。可以用该类来创建对话框而不是用Acitivity类中的对话框辅助方法来创建,这样就可以将一个片段对话框加入由活动所管理的片段的返回栈,令用户可以返回到一个已被舍弃的片段。

ListFragment

显示一个由某一适配器(例如SimpleCursorAdapter)管理的项目列表,类似于ListActivity。它提供了好几种管理列表视图的方法,例如onListItemClick()回馈方法以处理点击事件。

PreferenceFragment(偏好设置片段)

以列表方式显示一个Preference对象的层级,类似于PreferenceActivity。当为程序创建“设置”活动时这是很有用的。

添加用户界面

一个片段通常被用于一个活动的用户界面,其自有的布局将成为该活动的一部分。

要为一个片段提供布局,就必须实现onCreateView()回馈方法,Android系统将在该片段绘制其布局时调用它。该方法的实现必须返回一个片段布局的根View。

注意:如果片段是一个ListFragment的子片段,那么默认的实现将从onCreateView()返回一个ListView,因此不必另外去实现该方法。

要从onCreateView()返回一个布局,可以从一个定义于XML中的布局资源中生成它。为此,onCreateView()提供了一个LayoutInflater对象。

例如,这里有一个Fragment的子类从example_fragment.xml文件中读取了一个布局:

被传递给onCreateView()的container参数是上一级的ViewGroup(来自于该活动的布局),片段的布局将被插入其中。savedInstanceState参数是在返回片段时提供之前片段实例数据的一个Bundle(将在“处理片段生命周期”一节中更深入地讨论状态恢复)。

创建一个布局

在上面的范例中,R.layout.example_fragment是指向保存于程序资源中的一个名为example_fragment.xml布局资源的引用。关于如何在XML中创建一个布局的更多信息,请参见“用户界面”文档。

inflate()方法需要三个参数:

  • 希望生成的布局的资源ID
  • 要生成的布局的父级ViewGroup。为了使系统将布局参数传递给生成的布局的根视图,就需要传递该container。这将由当前正在运行的父视图来决定。
  • 一个表明了生成的布局在生成过程中是否应该和ViewGroup(即第二个参数)相关联的布尔值。(在这个例子里,因为系统已经将生成的布局插入到了container内所以值为false——如果是true则会在最终的布局中产生一个冗余的视图组。)

现在已经了解了如何创建一个提供了布局的片段。接下来,需要将该片段添加到活动中去。

向活动添加一个片段

通常,片段作为宿主活动的UI的一部分嵌于该活动整体视图层级之中。有两种方式可以将一个片段添加到活动的布局:

  • 在活动的布局文件里声明该片段。

这种情况下,如果片段是一个视图,可以为其指定布局属性。例如,这里有一个含有两个片段的活动的布局文件:

 <fragment>中的android:name属性指定了用来实例化布局的Fragment类。

当系统创建该活动布局时,将实例化在布局中指定的每一个片段并为其调用onCreateView()方法来检索每一个片段的布局。系统将在<fragment>元素处直接插入由该片段返回的View。

注意:每一个片段需要在系统中有一个唯一的标识用以在活动重启时还原该片段(并且用于获取该片段以执行如移除该片段之类的操作)。有三种方式提供一个片段的ID:

    • android:id属性提供唯一的ID。
    • android:tag属性提供唯一的字符串。
    • 如果没有提供以上两种标识,系统将使用其容器视图的ID。

 

  • 或者,在程序中将片段添加至已有的ViewGroup。

在活动正在运行中的任意时刻,都可以将片段添加至活动的布局。只需要指定这一需要放置片段的ViewGroup即可。

要在活动中进行片段事务(例如添加、移除或替换一个片段),必须使用FragmentTransaction所提供的API。可以像这样在Activity中获取一个FragmentTransaction的实例:

之后可以用add()方法添加一个片段,指定要添加的片段以及要插入该片段的视图。例如:

传递给add()的第一个参数是该片段应当被放置的ViewGroup,通过资源ID来指定,第二个参数则是要添加的片段。

一旦通过FragmentTransaction进行了变更,比如调用commit()来使变更生效。

添加没有UI的片段

上面的范例演示了如何添加提供了UI的片段至活动中。不过,也可以通过使用一个片段来在活动中执行后台行为而不显示额外的UI。

要添加没有UI的片段,需要在活动中通过使用add(Fragment, String)来完成(为片段提供一个唯一的”tag”字符串而非一个视图ID)。这样就能添加该片段,但是,因为它没有和活动布局中的某个视图相关联,所以将不会收到onCreateView()的调用。因此不需要去实现这个方法。

为片段提供一个字符串标签(tag)对于无UI片段来说并不是很严格的要求——也能为包含UI的片段提供标签——但如果片段不含UI,那么字符串标签就是唯一能识别该片段的方式了。如果希望之后能从活动中获取该片段,需要使用findFragmentByTag()。

关于将片段作为后台工作部件而不含UI的活动的范例,请参见FragmentRetainInstance.java范例。

管理片段

要在活动中管理片段,需要使用FragmentManager。可以通过在活动中调用getFragmentManager()来获取它。

借助FragmentManager可以做到包括以下这些事:

  • 通过findFragmentById()(适用于在活动布局中提供了UI的片段)或findFragmentByTag()(对于提供了或没有提供UI的片段都适用)来获取已存在于活动之中的片段。
  • 通过popBackStack()将片段从返回栈中弹出(模拟了一次用户按下BACK键的指令)。
  • 通过addOnBackStackChangedListener()为返回栈的变化注册一个监听器。

关于这些方法的更多信息,请参见FragmentManager类的文档。

正如在之前一节中所描述的,还可以使用FragmentManager来打开一个FragmentTransaction,以能够执行例如添加、移除片段等事务。

执行片段事务(Fragment Transaction)

在活动中使用片段的一大特点是可以根据用户交互对这些片段进行添加、移除、替换或是执行其他操作。对活动进行的每一组改变都被称为是一次事务(transaction),可以通过FragmentTransaction提供的API执行事务。还可以把每一个事务都保存至活动所管理的返回栈,使得用户可以撤销片段的改变(和返回上一个活动类似)。

可以像这样从FragmentManager获取一个FragmentTransaction的实例:

每一个事务都是一组能同时执行的变更。可以通过对给定操作使用如add()、remove()和replace()等方法在设置所有希望执行的变更。之后,必须对活动调用commit()来应用该事务。

不过,在调用commit()之前,需要调用addToBackStack(),以将该事务加入片段事务的返回栈中。该返回栈由活动所管理,允许用户通过按下返回键来返回到之前的片段状态。

例如,下面展示了如何替换一个片段,并将之前的状态保存于返回栈中:

在这个范例里,newFragment替代了当前在由ID R.id.fragment_container定义的布局容器中的(任意的)片段。通过调用addToBackStack(),替换事务被保存于返回栈中,因此用户可以通过按下返回键来回滚事务,回到之前的片段。

如果将多次变更添加至事务(例如第二个add()或是remove())并调用addToBackStack()的话,那么所有在调用commit()之前被应用的变更都将作为一个单独的事务被加入返回栈中,BACK键将会恢复所有这些变更。

向FragmentTransaction中添加变更的顺序是无所谓的,不过:

  • 必须在最后调用commit()
  • 如果将多个片段加入同一个容器中,那么添加的顺序将决定它们在视图层级中的顺序

如果在执行移除片段的事务时没有调用addToBackStack(),那么该片段将在事务被执行(commit)后被销毁,用户无法再次返回它。反之,如果在移除片段时调用了addToBackStack(),那么该片段将被中止(stop),并在用户返回时被继续(resume)。

提示:对于每个片段事务,都可以通过在执行(commit)之前调用setTranstition()以应用一个切换动画。

调用commit()并不会立即执行事务。它只是作了在活动的UI线程(“主”线程)准备好之时运行该事务的调度。不过,如有必要,可以在UI线程中调用executePendingTransactions()来立即执行由commit()提交的事务。只有在该事务是其他线程工作的组成部分时才有必要这么做。

注意:可以仅在活动保存其状态之前(当用户离开活动时)使用commit()来执行一次事务。如果在此之后执行,将抛出一个异常。这是因为如果活动需要被储存的话,执行之后的状态将无法被保存。对于丢失状态也无妨的情况,则需使用commitAllowingStateLoss()。

和活动进行通信

尽管一个Fragment被作为一个独立于Activity的对象使用,且可以被用于多个活动之中,一个给定的片段实例可以与包含它的活动直接关联。

特别要注意的是,片段可以以getActivity()来获取Activity的实例,并能够在活动的布局中很容易地进行寻找视图之类的任务:

类似的,活动可以通过findFragmentById()或findFragmentByTag()从FragmentManager获取一个Fragment的引用来调用片段内的方法。例如:

创建活动接受的事件回馈

在有些情况下,可能会需要片段与活动共享事件。这可以通过在片段定义一个回馈接口并在宿主活动中实现它来实现。当活动通过该接口接收到了一个回馈时,如有需要,它可以与布局中的其他片段共享信息。

例如,如果一个新的应用程序在一个活动中有两个片段——一个用来显示一列文章(片段A)而另一个用来显示某一篇文章(片段B)——那么片段A必须在某一个列表项目被选中时告知活动,使活动能够告知片段B来显示该文章。在这种情况下,OnArticleSelectedListener接口被声明于片段A内:

之后持有该片段的活动实现了OnArticleSelectedListener接口并覆盖了onArticleSelected()来将来自于片段A的事件通知给片段B。为确保宿主活动实现了该接口,片段A的onAttach()回馈方法(当把片段添加至活动时系统将会自动调用该方法)通过将传递过来的Activity强制转换为了onAttach()以实例化了一个OnArticleSelectedListener的实例:

如果该活动没有实现这个接口,那么片段将会抛出一个ClassCastException。一旦成功实现了该接口,mListener成员将持有一个活动的OnArticleSelectedListener实现的引用,因此片段A将可以通过调用由OnArticleSelectedListener接口定义的方法和活动共享事件。例如,如果片段A是ListFragment的一个继承,那么每次用户点击一个列表项目时,系统将调用片段的onListItemClick(),它将之后调用onArticleSelected()来与活动共享该事件:

传递给onListItemClick()的id参数是被点击项目的行ID,它被活动(或其他片段)用来从应用程序的ContentProvider中获取文章。

关于使用内容提供器的更多信息请参见“Content Providers文档”。

添加项目至动作条(Action Bar)

片段可以通过实现onCreateOptionsMenu()方法来和活动的选项菜单(Options Menu)项目相结合使用(因此也就可以和动作条一起使用)。不过,为了使该方法能够接受调用,必须在onCreate()中调用setHasOptionsMenu()来标识该片段将被添加至选项菜单(否则,该片段将不会接收到对onCreateOptionsMenu()的调用)

之后从片段添加至选项菜单的任何项目都将被增加到已有菜单项目之后。该片段还将在某一菜单项目被选中时收到onOptionsItemSelected()的回馈。

也可以在片段布局中注册一个视图,通过调用registerForContextMenu()来提供上下文菜单。当用户打开上下文菜单时,该片段将收到一个对onCreateContextMenu()的调用。当用户选中一个项目时,片段将收到一个对onContextItemSelected()的调用。

注意:尽管片段对每一个添加过的项目都能收到一个项目选中回馈,但活动本身将在用户选择菜单项目时首先收到相应的回馈。如果活动的项目选中回馈的实现没有处理该选中的项目,那么该事件才会被传递给片段的回馈方法。对于选项菜单和上下文菜单来说都是如此。

关于菜单的更多信息,请参见“菜单”和“动作条”开发者指南。

处理片段生命周期

管理一个片段的生命周期和管理一个活动的生命周期十分的相像。如同活动一样,一个片段可以以三种状态存在:

Resumed

该片段在运行中的活动里是可见的。

Paused

另一个活动正处于前台且获得了焦点,不过含有该片段的活动依然是可见的(前台的活动是半透明的或没有覆盖整个屏幕 )。

Stopped

片段不可见。或是宿主活动被停止了,或是片段被从活动中移除后加入了返回栈。一个被停止的片段依然是存在着的(所有的状态和成员信息由系统保持着)。不过,它对于用户不再可见,在活动被杀除后也将被杀除。

和一个活动一样,可以通过一个Bundle以在活动的进程被杀除而又需要在该活动被重建时还原该片段的情况下保存片段的状态。可以在活动的onSaveInstanceState()回馈方法中保存状态,在onCreate()、onCreateView()或onActivityCreated()中还原状态。关于保存状态的更多信息,请参见“活动”文档。

图 3. 活动生命周期对于片段生命周期的影响

一个活动和一个片段的生命周期之间最大的区别在于它们是如何被保存于各自的返回栈中的。一个活动默认为在其被停止时被放入由系统所管理的一个返回栈中(这样用户就能通过BACK键返回该活动,就像“任务和返回栈”中所说的那样)。然而, 一个片段只有在进行片段移除的事务中调用addToBackStack()来显式地请求保存片段的实例时才会被放入由宿主活动所管理的返回栈中。

除此之外,管理片段的生命周期和管理活动的生命周期十分相似。因此,管理活动生命周期时的做法同样可以应用于管理片段。所需要理解的就仅仅是活动的生命周期将会地片段的生命周期有着怎样的影响。

范例

为了总结本文档中所说的,下面有一个范例来演示一个使用了两个片段的活动是如何创建一个双面板布局的。下面的这个活动包含了一个显示一列莎士比亚戏剧标题的片段和另一个在从列表中选择项目后显示该戏剧的摘要的片段。它还演示了如何基于不同的屏幕配置来提供不同的片段配置。

注意:该活动的完整源代码可以在FragmentLayout.java中得到。

主活动按照常规的方式在onCreate()中应用布局:

被应用的布局是fragment_layout.xml

使用该布局,系统将在活动载入该布局时实例化TitlesFragment(它列出了戏剧标题),而FrameLayout(它显示戏剧的摘要)将占用屏幕的右侧(不过最初它是空着的)。可以发现,直到用户从列表中选择了一个项目之后某一个片段才会被放入FrameLayout。

不过,不过所有的屏幕配置都足够宽来在两边显示戏剧列表和摘要。所以上面的布局仅用于横屏模式,需要保存为res/layout-land/fragment_layout.xml

因此,当屏幕是竖向时,系统将应用下面的保存于res/layout/fragment_layout.xml的布局:

该布局仅包含了TitlesFragment。这意味着当设备处于竖向状态时,只有戏剧标题列表是可见的。因此,当用户在这时点击了列表项目的话,程序会启动一个新的活动来显示摘要,而不是载入第二个片段。

接下来,看一下如何在片段类中完成整个过程。首先是TitlesFragment,它显示了一列莎士比亚戏剧标题。该片段继承于ListFragment,通过它来处理大部分的列表视图工作。

正如代码中所表明的,需要注意当用户点击一个列表项目时有两种可能的行为:这取决于两种布局中的哪一种使处于激活状态的。它既可以在同一个活动中创建并表示一个新的片段来显示详细信息(将片段加入FrameLayout),也可以启动一个新的活动(并在那里显示片段)。

第二个片段,DetailsFragment显示了从TitlesFragment列表中所选择的戏剧项目的摘要:

回忆一下TitlesFragment类,如果用户点击了一个列表项目时当前布局没有包含R.id.details视图的话(DetailsFragment属于该视图),应用程序将启动DetailsActivity活动来显示项目的内容。

下面是DetailsActivity,它仅仅内嵌了DetailsFragment以在屏幕处于竖屏模式时显示所选择的戏剧摘要:

注意这个活动在横屏模式时将会自动结束,改为由主活动同时显示DetailsFragmentTitlesFragment。而在用户以竖屏模式启动DetailsActivity之后旋转屏幕至横屏模式的情况下也会如此(此时将重启当前活动)。

关于使用片段的更多范例(以及本范例的完整源文件),请参见ApiDemos里的范例代码(可以从范例SDK组件中下载)。

本页部分内容根据Android Open Source Project创作并共享的内容修改,并在知识共享 署名2.5许可协议中所述条款的限制下使用。

NTT DOCOMO闪电发表Xperia PLAY SO-01D

日本电信运营商NTT DOCOMO今天闪电发表了索尼爱立信(Sony Ericsson)制Android智能手机Xperia PLAY SO-01D,也就是Xperia PLAY的日本版本。

两者之间本身没有特别的区别,但是相信今后Xperia PLAY可用的日式游戏数量也会渐渐增加了吧。

Xperia PLAY SO-01D预计于2011年10~11月发售。

索尼(SONY)发表搭载了Android系统的Walkman Z系列等,音质、性能均为史上最高

索尼(SONY)今天正式发表了旗下Walkman家族新成员Z系列,以及A系列和S系列的最新型号。

搭载了Android 2.3操作系统的Walkman Z系列将于今年12月10日正式发售。Z系列采用了4.3英寸的WVGA分辨率(800×480像素)高亮度高对比度触摸屏,并使用了高端平板电脑中广泛采用的NVIDIA Tegra 2处理器(1GHz,双核)及512MB运行内存。Android Market上的应用下载、高速网页浏览、高清视频播放等功能一应俱全。

Walkman Z系列具有黑、红两种色彩,16GB、32GB和64GB三种容量版本。外形尺寸约为70.5×约134.2×约11.1mm(最薄处:9.6mm)、重量约156克。电池续航时间为音乐约20小时,视频约5小时。

其背面设有单声道扬声器,同时支持DLNA、支持IEEE802.11 b/g/n标准的WLAN、HDMI接口、Bluetooth 2.1+EDR以及GPS、电子罗盘、加速度传感器、FM收音机等。

能够降低98%周围噪音的“digital noise cancelling”技术自然不必多说,能实现Walkman史上最高音质的“S-Master MX”全数字放大器,能够还原清澈高音的“DSEE(Digital Sound Enhancement Engine)”,抑制左右声道混音的“Clear Stereo”以及提供清澈低音的“Clear Bass”技术都被一并采用。此外高低音域平衡修正的“Clear Phase”技术,增强耳机临场感的“VPT”技术进一步确保了Walkman Z系列的音质。

此外,操作更为便捷的“W.Music”播放界面,以及在屏幕关闭状态下也能控制音乐播放的“W.Button”使得Walkman Z的易用性也更上一层。

Walkman Z系列的新闻稿(日文)以及产品页面(日文)。

尽管常常会有规格下降,不过通常国内行货都会引进Walkman系列的高端型号,因此预计在不久的将来行货的Walkman Z系列也将会被引进。

此外,今天索尼同时正式发表了Walkman A系列和S系列的最新型号A860系列、S760系列。

A860系列在音质上和Z系列有着相同的高规格,同样搭载了“digital noise cancelling”技术、“S-Master MX”全数字放大器、“DSEE”、“Clear Stereo”以及“Clear Bass”技术。2.8英寸的TFT触摸屏以及蓝牙支持也是相对于前辈的一大进步。

之前型号所具有的各种功能在A860上依然得到保留。目前已确定将引进国内行货,不过很可惜的是在软硬件功能上将会有一定的区别与限制。

A860系列产品页面(日文)。

中端的Walkman S系列也对产品线进行了更新。新的S760系列虽然没有搭载“S-Master MX”,但是其他诸如“digital noise cancelling”技术、“DSEE”、“Clear Stereo”以及“Clear Bass”技术的加持使其仍然保持了出色的高音质。同时也A860系列一样,S760系列也支持蓝牙音乐传输,并提供了随机搭配了蓝牙立体声耳机的S760BT套装。

S760系列产品页面(日文)

A系列化以及S系列发布的新闻稿(日文)。

A系列与S系列都将于近日于日本发售,国内行货则是已经推出。行货产品页面。稍微留意了下,主要区别似乎都是去除了内置降噪功能而需要通过降噪耳机实现降噪,内存容量也相对较小。

文中所有图片版权属于Sony Corporation。

Android用记事本程序 Techo Lite 版本升级 1.2.0

昨晚对Techo Lite进行了一次小型的改进,说明如下:

Techo Lite是一款以快速启动和功能精简为特色的Android用记事本软件。编写的初衷是为了能有一个只需一次按键就能立即开始文字输入且不必考虑保存、打开等问题的便筏。

关于之前版本的相关信息,请参见当时的发布日志

这次的1.2.0升级除了一些细节问题的修正外,主要提供了两项新功能。其一是文本文件导出功能,可以将当前记录内容以.txt格式保存于SD卡,在一定程度上解决了Techo Lite泛用性较低的不足。另一功能为“撤销清除”功能,可以恢复最近一次的“清除”当前内容的操作,其用意是解决误操作。

今后计划改进的方面为对平板电脑的优化,这将在入手Tablet S之后着手进行。同时正在考虑是否需要为其加入导入功能。同时全功能版的记事本Techo也正在设计中,或许那才是真正的终点。

Android Market页面:

https://market.android.com/details?id=org.breezesoft.techolite

一些新版的程序截图:

索尼(SONY)展出平板设备Tablet系列、新型电子书阅读器,发表Xperia arc S等

在当地时间8月31日于德国柏林举办的世界最大规模消费电子展会IFA2011上索尼(SONY)一口气展出、公布了大量新产品。

首先是备受瞩目的索尼平板设备,Tablet S与Tablet P。

Sony Tablet是搭载了Android 3.2(Tablet S在发售时暂时搭载3.1版本)的平板电脑,以流畅的操作感和丰富的网络应用为卖点。平板型的Tablet S将于9月17日发售Wifi版的16GB/32GB两种型号,而在10月或11月则将发售折叠型的Tablet P的3G+Wifi版以及3G+Wifi的16GB版Tablet S。

Tablet S搭载了一块9.4英寸的触摸屏,重量约598g,采用了NVIDIA® Tegra™ 2 处理器。Tablet P则是上下两块5.5英寸的屏幕,折叠后尺寸约180mm × 26mm × 79mm,重372g。

Tablet S采用了特别的人体工学设计,使得长期把持也不容易感到疲劳。Tablet P则是由双屏设计而提供了更多可能性。两者均内置了大量的索尼自制软件以提升易用性,以及Video Unlimited、PlayStation Certified、Reader Store、Personal Space by Sony等索尼提供的娱乐/便利服务。系统上索尼对虚拟键盘等各个细节做了针对性的优化以优化使用体验。

两者均提供了包括外接蓝牙无线键盘在内的种类丰富的配件,其中Tablet S还支持支架。

Tablet S的Wifi 16GB版售价约45000日元(折合人民币约3750元),32GB版约53000日元(折合人民币约4400元)。

Sony Tablet目前还没有任何国内行货的消息,自己是已经决定通过网络入手了。

Sony Tablet官方新闻稿见这里(日文)。

与Sony Tablet同时发布消息的还有新型号的电子书阅读器PRS-T1。这款产品在前几天就已经流出了不少消息,而在IFA2011上终于正式发表。

与早先型号的PRS-650/350相比,PRS-T1增加了Wifi支持(可不经由电脑购买书籍)、多点触摸屏幕(支持缩放等功能)、多语言词典以及Wikipedia/Google便捷搜索等功能。屏幕则依然是6英寸的E-ink屏。

与此同时索尼还宣布将在欧洲国家展开Reader Store电子书商店服务,英国将在今年10月末开始,德国与奥地利在今年末,法意西则预计明年春季开始。英国首发就将能够提供10万册书籍。

新型Reader电子书阅读器PRS-T1的官方新闻稿见这里(日文)。

手机方面则是发表了今年大受好评的Xperia arc的改良版Xperia arc S已经使用了Walkman商标的Android手机。

相比前代产品Xperia arc,Xperia arc S搭载了一颗1.4GHz的处理器(基于高通MSM8255 platform平台的512 MB RAM及1.4 GHz Snapdragon处理器,配合Adreno 205 GPU),能提供高出Xperia arc约25%的处理性能。系统则是将于上市时使用Android 2.3.4,和其他2.3.4机型一样,Xperia arc S将具备3D全景拍摄功能等新特性。

其他方面Xperia arc S则基本与前辈相当。4.2英寸的16M发色数FWVGA分辨率屏幕,Reality Display with Mobile BRAVIA® Engine保证的显示效果优化,Exmor R™ for mobile提供的优异拍摄效果等。

色彩方面Xperia arc S提供了纯白、午夜蓝、神秘银、钢琴黑以及樱粉五种色彩,相信能满足更多人的喜好。

预计2011年第四季度全球发售。

Xperia arc S的官方新闻稿见这里(英文)。

Xperia arc S的产品页面见这里(英文)。

至于另一部Android系统的Walkman手机则还没有太多的消息,不过似乎依然只是中端型号。将继续对其进行关注。

最后是昨天闪电发表的头戴式3D显示器HMZ-T1。

这是世界上第一台民用头戴显示设备。采用了两块1280×720分辨率的OLED屏幕,支持3D立体影像。OLED则提供了高对比度、优秀色彩表现以及快速响应能力。左右双屏幕提供了区别于以往的FS或LBL式3D原理的更为自然舒适的3D效果。此外它还具有5.1声道环绕声输出,提供了上佳音质水平。

该头戴式显示器为有线式,需要连接外置机盒,重量约420g。

HMZ-T1预计售价约60000日元(折合人民币约5000元),将于今年11月11日发售。目前没有行货的消息。

官方新闻稿见这里(日文)。

产品页面和效果演示视频见这里(日文)。

文章中所有图片版权属于Sony Corporation

构造自定义组件

Android提供了一种高级而强大的自定义模型来构建UI,这一模型基于布局类View和ViewGroup来实现。首先,Android平台包含了一系列的预构建View和ViewGroup子类——被称为控件(widget)和布局(layout)——用以构造UI。

可用的控件包括但不限于Button、TextView、EditText、ListView、CheckBox、RadioButton、Gallery、Spinner及一些特殊用途的AutoCompleteTextView、ImageSwitcher和TextSwitecher。

可用的布局包括LinearLayout、FrameLayout、RelativeLayout等。范例请参见“常见布局对象”。

如果预构建的控件或布局无法满足需要,可以创建自有的View子类。如果只是要对现有的控件或布局作小调整,可以继承该控件或布局并覆盖其方法。

通过创建自有的View子类,将可以对于屏幕元素的外观和功能进行精确控制。要了解能够对自定义视图进行哪些控制,可以参考下面的例子:

  • 可以创建一个完全自定义渲染的View类型,例如使用2D图像渲染的有些类似于模拟电路控制的“音量控制”按键。(自己也不太清楚analog electronic control是什么,总之这个例子是说可以自定义按键的外观)
  • 可以将一组View组件结合为一个新的单独的组件,比如类似于ComboBox(一种弹出式列表和文本输入栏的结合体)的东西,或是双栏选择器(一种有左右两栏的列表,可以重新分配其中的某个项目应该属于哪一栏),等等。
  • 可以覆盖EditText组件在屏幕上的渲染方式(Notepad教程中通过这种方式创建了具有划线的记事本页面,取得了良好效果)
  • 可以捕捉例如按键等的其他事件并以自定义方式处理它们(例如在游戏中)。

下面的小节阐述了如何创建自定义View并将其用于程序之中。更为详细的参考信息,请参见View类。

基本方式

这里是对要创建自有View组件所需了解的内容的一个高度预览:

  •  用自有类继承一个View类或其子类。
  • 覆盖其中的一些方法。需要覆盖的是那些父类中以“on”开头的方法,例如,onDraw(),onMeasure()和onKeyDown()。这和在Activity或是ListActivity中覆盖那些和生命周期与功能相关on…事件相类似。
  • 使用该新类。一旦完成,自有的新类可以被用于其父类能被用于的地方。

 提示:继承的类可以在使用它们的活动中被定义。这样就限制了对其不必要的使用,很有用(因为可能会为了更广泛的用途而需要在程序中创建另一个新的公用View)。

 完全自定义的组件

完全自定义的组件可以被用来创建任何希望呈现的图形组件。也许是一个看起来像是老式类比指示条的音量指示器,或是卡拉OK机上唱歌时会有一个随着歌曲的进度弹跳着的小球的一长条的文本视图。总之,有时无论怎样组合预置组件也无法达到某种效果,因而需要另外的自定义组件。

幸运地,可以轻松地创建具有所希望的外观和行为的组件,仅有的限制只是想象力,屏幕尺寸,可用的处理器能力(要记得最终程序不得不运行于比桌面工作站性能弱很多的设备上)。

要创建一个完全自定义的组件:

  1. 也许有些出乎意料,通常要继承的视图正是View,因此创建新的组件往往以继承View类开始。
  2. 可以提供一个构造函数以从XML中获取属性和参数,也可以自己定义这些属性和参数(比如音量指示器的色彩和范围,指针的宽度和阻尼等。)
  3. 有可能需要为该组件创建自有的事件监听器,属性继承器和修改器,或是其他更为深入的功能。
  4. 通常都需要覆盖onMeasure()方法,如果希望组件显示内容,常常onDraw()方法也要覆盖。这两者都具有其默认行为,默认来说onDraw()什么也不做,而onMeasure()则总是设置尺寸为100×100——这可能不是所希望的属性。
  5. 如有需要其他的on…方法也应该被覆盖。

 继承onDraw()和onMeasure()

onDraw()方法将传递一个Canvas,在该Canvas上可以实现任何所需内容:2D图形、其他自定义组件、个性化的文本内容或其他所能想到的。

注意:这并不适用于3D图形。如果希望使用3D图形,必须继承SurfaceView而不是View,并在另一个线程中绘制。参见GLSurfaceViewActivity范例以了解更多。

onMeasure()则稍微复杂一些。onMeasure()是组件与其容器之间的一种渲染约束。它应该被覆盖以高效而准确地报告其所包含内容的尺寸度量。由于其父级(它被传递给onMeasure()方法)限制的要求,又由于一旦完成计算后需要以测量的宽度和高度来调用setMeasuredDimension(),整件事变得有些复杂。如果没能通过一个被覆盖的onMeasure()方法来调用它的话,结果将会是在测量时抛出一个例外。

从整体上来看,实现onMeasure()大致是这样的:

  1. 被覆盖的onMeasure()方法被以宽度和高度的测量值(即widthMeasureSpec以及heightMeasureSpec参数,它们都是用来表示维度的整型值)调用,这是对于要处理的宽度和高度的测量值的一种限制。这些参数能够要求的所有限制的参考资料请见View.onMeasure(int, int)相关的文档(该参考文档同时很好的解释了整个测量操作)。
  2. 组件的onMeasure()方法应当计算出渲染该组件所需的宽度和高度的测量值。它通常应当和传入的参数相匹配,不过有时也可以选择扩大(这时,父类可以根据不同的测量值选择包括切割、滚动、抛出例外或请求onMeasure()重试等一系列操作。)
  3. 一旦宽度和高度被计算出来,就必须以它们去调用setMeasuredDimension(int width, int height)。否则将导致抛出例外。

下面是关于视图的框架可能调用的其他标准方法的一些总结:

类别 方法 描述
创建 构造函数 在通过代码创建视图时和在视图通过布局文件生成时都会需要一些构造函数。第二种情况下布局文件中定义的任何属性都需要被读取并应用。
onFinishInflate() 当一个视图及其所有子视图都通过XML生成后被调用。
布局 onMeasure(int, int) 调用以决定该视图及其所有子视图所需的尺寸。
onLayout(boolean, int, int, int, int) 当该视图需要指定其所有子视图的尺寸和位置时被调用。
onSizeChanged(int, int, int, int) 当该视图的尺寸发生变化时被调用。
绘制 onDraw(Canvas) 当该视图需要渲染其内容时被调用。
事件处理 onKeyDown(int, KeyEvent) 当一个新的按键事件发生时被调用。
onKeyUp(int, KeyEvent) 当一个按键释放事件发生时被调用。
onTrackballEvent(MotionEvent) 当一个轨迹球移动事件发生时被调用。
onTouchEvent(MotionEvent) 当一个触摸屏动作事件发生时被调用。
焦点 onFocusChanged(boolean, int, Rect) 当视图获得或是失去焦点时被调用。
onWindowFocusChanged(boolean) 当包含了该视图的窗口获得或是失去焦点时被调用。
关联(Attaching) onAttachedToWindow() 当该视图与一个窗口相关联后被调用。
onDetachedFromWindow() 当该视图与窗口接触关联后被调用。
onWindowVisibilityChanged(int) 当包含了该视图的窗口的可见性发生改变时被调用。

 一个自定义视图的范例

在API Demos中的CustomView范例提供了一个自定义View的范例。该自定义View被定义在LabelView类中。

这个LabelView范例对自定义组件的各方面进行了演示:

  • 继承View类来创建一个完全自定义的组件。
  • 支持参数并可以接受视图生成参数(在XML中定义的参数)的构造函数。其中一些参数将被传递至父类View,不过更重要的是,一部分参数将被用于在LabelView中定义的属性。
  • 一些该标签组件所需的标准公有方法,比如setText()setTextSize()setTextColor()等等。
  • 被覆盖的onMeasure()方法以决定并设置组件的渲染尺寸。(注意在LabelView中,实际的工作是由私有的measureWidth()方法完成的。)
  • 被覆盖的onDraw()方法以将标签绘制于所提供的画布(canvas)上。

可以在范例中的custom_view_1.xml里看到一些LaberView自定义视图的用例。通常,可以看到android: namespace参数和自定义的app: namespace参数被混合使用。app: parameters是LabelView进行组织并使用的参数,被定义于该范例的R资源定义类中的风格化内部类中。

复合控制器(Compound Control)

如果不想创建一个完全自定义的组件,而是希望将一些可重用的组件组合在一起以获得一组已存在的控制功能的话,就创建一个复合组件(或称为复合控制器)吧。简言之,就是将一些更为基本的控制器(或是视图)装入一个逻辑组使之被看作为是一个单独的组件。例如,一个Combo Box可以被认为是一条单独的EditText域加上一个具有弹出式列表(PopupList)的调节按钮。如果按下按钮并从列表中进行选择,就会弹出一条EditText域,当然用户也可以直接在EditText中键入一些内容。

在Android中,其实已经有两种View可以做到这点了:Spinner和AutoCompleteTextView,不过Combo Box的概念还是可以用来做为一个简单易懂的范例的。

要创建一个复合组件:

  1. 这通常是从某种类型的Layout开始,所以需要创建一个继承了某种Layout的类。在Combo box的例子中或许应该使用一个水平方向的LinearLayout。请记得其他的布局是可以嵌套于其中的,所以复合组件可以做得相当地结构复杂。需要注意的是还可以像Activity所使用的那种方式一样通过声明式(基于XML)的方式来创建所包含的组件,或是在代码中对其进行嵌套。
  2. 在新类的构造函数中,获取父类所需的所有参数,并首先将其传递给父类的构造函数。之后可以设置其他在新的组件中所要使用的视图;在这里将创建EditText域和PopupList。请注意可能还需要向XML引入一些自有属性和参数用以被提取并使用于构造函数。
  3. 还可以为所包含的视图可能会触发的事件创建监听器,例如,一个当进行了列表选择后对EditText的内容进行更新的列表项目点击监听器(List Item Click Listener)的监听器方法。
  4. 还可以通过访问器(accessor)和修改器(modifier)创建自有的属性,例如,允许EditText的值在组件中被初始化并在需要时可以查询获取其内容。
  5. 在继承一个Layout时,不必覆盖其onDraw()onMeasure()方法,因为该布局的默认行为就能很好的实现效果。不过,如有需要还是可以对其进行覆盖。
  6. 可以覆盖其他的on…方法,例如onKeyDown(),用于某个键被按下时从一个combo box的弹出列表中选择某一个默认值。

总之,使用Layout作为自定义控制器的基础将带来一系列的好处,包括:

  • 可以通过和活动一样的声明式的XML文件来指定布局,或是可以在代码中创建视图并将其嵌入布局中。
  • onDraw()onMeasure() 方法(加上大部分其他的on…方法)的默认行为能正常工作因而不必进行覆盖。
  • 最后,可以很快捷地构建非常复杂的复合视图并重复利用它们。

复合控制器的范例

在SDK附带的API Demos项目中,有两个List范例——Views/Lists下的范例4和范例6演示了一个继承了LinearLayout的SpeechView,它构建了一个显示Speech引用的组件。范例代码中所用的相关的类是List4.javaList6.java

修改一个已有的View类型

在某些情况下可以用一种更简单的创建自定义View的方法。如果已经有了一个和所希望创建的组件非常相似的组件,可以继承该组件并覆盖那些希望改变的行为。可以像对完全自定义的组件那样对这个继承的组件进行任何处理,只不过是需要从View层级中一个更为特殊化的类开始罢了。与此同时还可以额外获得其他很多所需要的功能。

例如,SDK在范例中包含了一个NotePad程序。它演示了使用Android平台的许多方面,包括继承一个EditText View来实现带有划线的记事本。这并不是一个完美的范例,且实现这个效果的API相对这个比较早期的版本可能会发生改变,不过它确实展示了一些使用原则。

如果还没有尝试过,那就将NotePad范例导入到Eclipse(或只是查看所提供的链接中的源代码)。特别是查看NoteEditor.java文件中MyEditText的定义。

其中一些要点如下。

1. 定义

该类由以下代码定义:

public static class MyEditText extends EditText

  • 它被定义为NoteEditor活动的一个内部类,不过因为它是公有的所以可以在需要时从NoteEditor外部以NoteEditor.MyEditText被使用。
  • 它是静态的,意味着它不会生成所谓的“合成方法(synthetic method)”以允许它读取其父类的数据。这同时也意味着它是一个具有独立行为的类,并没有和NoteEditor保持着高度相关性。这是创建不需要读取外部类的数据的内部类时一种比较条理清楚的做法,它使得生成的类较小且能被其他类所使用。
  • 在这里EditText被选作需要自定义的View来被它继承。当完成后,一个新的类可以用来替代通常的EditText视图。

2. 类初始化

和往常一样,super被首先调用。另外,这不是一个默认的构造函数,而是包含了一些的参数。EditText在通过XML布局文件生成时将用到这些参数,因此,新的构造函数也要获取这些参数并将其传递给父类的构造函数。

3. 覆盖方法

在该范例中,只覆盖了一个方法:onDraw() —— 不过当创建自己的自定义组件时很可能需要覆盖更多方法。

对于NotePad范例来书,覆盖onDraw()方法使得能够在EditText视图的画布(canvas)上绘制蓝线(画布被传递给了被覆盖的onDraw()方法)。super.onDraw()方法在该方法结束前会被调用。这一父类方法的调用是必需的,不过在这里,它在完成了所希望的直线的绘制后才被最后执行。

4. 使用自定义组件

现在已经有了自定义的组件,不过该如何使用呢?在NotePad范例中,自定义组件被直接从声明式的布局中使用,所以现在来看下res/layout文件夹下的note_editor.xml

*该自定义组件作为通用视图在XML中被创建,且该类被指定为使用整个包。还要注意所定义的内部类通过NoteEditor$MyEditText标识来引用,这是Java编程语言中引用内部类的标准方式。

如果自定义的View组件没有作为内部类被定义,那么还可以用XML元素名称来声明该View组件而不包括class属性。例如:

注意现在的MyEditText类是一个单独的类文件。当这个类被嵌套于NoteEditor类中时,这样的做法将会有问题。

*定义中的其他属性和参数将被传递至自定义组件的构造函数,之后被传入EditText的构造函数,即这些也是EditText所需要使用的参数。注意还可以增加自有参数,之后还会涉及这一问题。

该范例的说明至此。确实这只是个简单的例子,但它演示了关键点——可以根据需求创建任何复杂的自定义组件。

一个更为复杂的组件可能需要覆盖更多的on…方法并且引入一些自有的方法以完全自定义其属性和行为。唯一的限制就仅仅是想象力和实际需要组件去完成怎样的工作。

 返回用户界面

本页部分内容根据Android Open Source Project创作并共享的内容修改,并在知识共享 署名2.5许可协议中所述条款的限制下使用。

索尼爱立信(Sony Ericsson)发表新型号Android手机、2011年Xperia手机将得到Android 2.3.4系统升级

今天索尼爱立信正式发表了新型号的Android手机Xperia neo V以进一步扩充Xperia家族的产品线。

作为Xperia neo的后续机型(?),其卖点是将最先搭载索尼爱立信定制的Android 2.3.4系统于今年第四季度上市。相比前辈neo,neo V的摄像头有所削弱,规格上仅仅为500万象素且没有采用Exmor R for Mobile,不过将支持3D全景拍摄功能。前置摄像头配合新版系统将使其具备视频通话的能力。Moblie BRAVIA® Engine这一软件显示效果优化功能及HDMI输出功能则得以保留。其他硬件规格则基本与2011年机型相同。猜测neo V应该可以以一个较为有竞争力的价格上市。

另外索尼爱立信正式宣布了2011年Xperia机型获得2.3.4系统升级的日期。根据不同地区,计划于今年十月开始陆续发布升级。也就是说Xperia X10将不在这次升级机型之列。升级包含的改进点包括但不限于:

  • 具有前置摄像头的机型将具备视频通话功能
  • 由Sony提供的3D全景拍摄功能(我见过实际的拍摄效果,确实很有意思)
  • 增加一些USB扩展性外设支持
  • Swipe文本输入法
  • 任意情况下的屏幕截图功能

这次升级可以通过OTA下载,也可以通过PC Companion升级。

本文中出现的图像版权属于Sony Ericsson Mobile Communications AB。

索尼爱立信官方新闻稿见这里

索尼爱立信(Sony Ericsson)发表新型号智能Walkman手机

今天索尼爱立信正式发表了名为Sony Ericsson Live with Walkman™的音乐智能手机。这部搭载了最新Android 2.3系统的Walkman手机以发现和分享音乐为卖点,中端的定位相信也能提供合适的价格。

图像版权属于Sony Ericsson Mobile Communications AB

这部手机的特色为:

  • 深度整合Facebook,加强了分享功能
  • 音乐发现功能,了解朋友们正在听的音乐
  • 无线按钮,一键搜索音乐的各类相关信息
  • 来自SONY的Qriocity音乐视频服务,在线获取各类资源
  • Sony的xLOUD™技术,提升使用扬声器时高音量下的音质
  • 经典项目TrackID™功能,了解正在听的音乐的信息

而硬件上,3.2英寸HVGA分辨率(480×320)的电容式多点触摸屏幕是中端主流配置,500万像素自动对焦带LED补光灯的摄像头也比其前辈W8提升了不少。进入Android时代后Walkman手机和普通手机的差异越来越小,这或许也是大多数消费者对于音质也并不敏感所造成的吧结果吧。在Walkman品牌号召力不如从前的现在,真希望再能见到一款高端Walkman手机。

关于手机参数等信息的具体新闻稿见这里(英文)。

Android用日常事项管理软件 Routine 版本升级 1.2.0

如之前所说的,在X10得到了2.3.3升级之后,为了保持界面风格上的统一,花了点时间对Routine又进行了一次小幅升级。

Routine是一款Android平台的GTD软件,写这个程序的初衷是为了弥补没有很适合自己用的Xperia X10的GTD工具的遗憾。程序的特色就是使用了索尼爱立信的UXP主题,能够和X10家族的机型保持界面风格上的统一。这次升级的界面是以索尼爱立信UXP 3.0风格(当前使用Android 2.3.3系统的各款机型所使用的界面风格)为基础的,由于Xperia X8、Xperia X10 mini和Xperia X10 mini pro这三部旧机型没有得到Android 2.3.3以及最新界面风格的升级支持,因此在这次Routine的界面改变之后反而变得风格不一了。

除了界面的改变之外,还为条目内容新增加了截止日期项。更多的信息可以参见之前的更新日志

今后计划增加的功能有和Google在线To do List的同步、到期提醒、循环和多种方式排序等。

目前Routine可以在Android Market的效率类应用程序中找到,搜索Routine、ルーチン或者pub:BREEZE即可。如果需要一款简单好用的GTD工具,不妨试试看Routine吧。

Android Market页面:

http://market.android.com/details?id=org.breezesoft.routine

最后是一些新版Routine的程序截图:

Android中如何创建自定义ListView

综述

随着搭载了Android系统的设备数量越来越普及,对Android系统应用开发有兴趣的开发者也越来越多。各种类型的应用中都常常会使用到ListView。Android系统预先定义了一些ListView的类型,可以在官方发布的API Demos中找到。不过由于往往需要使用自定义的ListView来满足不同应用的设计需要,因此有必要了解Android系统中创建并使用自定义ListView的方法。本文结合个人的一些经验,期望能尽可能简明易懂地对这个问题进行说明。

本文的目标读者是具有一定的Java语言和Android开发基础的开发者。

本文将对一个具有图片(ImageView)、文本(TextView)和可选框(CheckBox)三种控件的自定义ListView的代码进行注释与详解,以供读者举一反三,创建并使用自己的自定义ListView。

本文所使用的开发环境为:

  • Windows 7
  • Eclipse Java IDE Version 3.7 (Indigo)
  • Oracle Java SE JDK 6 Update 26
  • Android SDK Version 2.3.3, API 10

(以上并非必要环境。相兼容的操作系统和较低版本的软件也可以完成本项目。)

代码

ListViewExampleActivity.java

.
.
ViewHolder.java

.
.
main.xml

.
.
itemrow.xml

.
.

说明

ListViewExampleActivity是本范例的主体。在onCreate函数中进行了准备工作,初始化了数据等,并提供了ListView的按键监听函数。在该类中包含了基于BaseAdapter 的自定义适配器ItemAdapter类。这是使用自定义ListView的关键。代码注释说明了各个部分的内容。其中getView()函数需要根据不同的自定义ListView的项目内容进行调整。本范例的项目包含图片、文本和CheckBox三项内容,因此getView()函数也相应地对这三项内容进行了操作。如果自定义的ListView项目包含更多内容,在这里进行相应的语句增添即可。

ViewHolder包含了单条项目中所要储存的数据。由于结构较为简单,故不多熬述。

main.xml是ListViewExampleActivity所使用的布局文件。在一个LinearLayout中包含了一个ListView。布局不是本文的主题,故在此不多熬述,可参见博客中的其他文章。

itemrow.xml是使用自定义ListView的另一关键。它使用一个RelativeLayout描述了单条项目中的图片、文本和CheckBox的相对位置关系。该内容亦不是本文的主题,更进一步的内容可参见博客中的其他文章。

简单地说,通过修改本范例中的refresh()函数、ItemAdapter中的getView()函数、ViewHolder类和itemrow.xml即可实现其他类型的ListView。

截图与资源

点此下载程序代码与资源

本文参加

第二届 Google 暑期大学生博客分享大赛 – 2011 Android 成长篇