第2章 Hello,Views
本章我们会选取几个类似“Hello World”的例子,并快速布局用来演示一些Views。
本章需要有一定的知识积累,开始之前你应该完成“Hello World”并且知道如何创建运行一个工程,了解一个工程的基本结构。以下是一些内容的预览
2.1布局
Linear Layout(水平布局) |
Relative Layout(相对布局) |
Table Layout(表格布局) |
Grid View(网格View) |
Tab Layout(选项卡布局) |
List View(列表View) |
表格2-1
2.2 Widgets和其他Views
Date Picker(日期选择器) |
Time Picker(时间选择器) |
Form Stuff(表单元素) |
Spinner(下拉列表) |
Auto Complete(自动完成) |
Gallery(画廊) |
Google Map View(谷歌地图) |
Web View(浏览器View) |
|
|
表格2-2
更多的View,大家可以参考android.widget.*包中的内容,下面我们开始单独讲解上面的例子。
2.1.1 Linear Layout
LinearLayout继承自ViewGroup,而ViewGroup继承自View。这种水平布局有横向和纵向的两种模式。我们应该小心的使用LinearLayout,如果有很多个LinearLayout的嵌套,我们可以考虑使用RelativeLayout来代替它。下面我们新建一个HelloLinearLayout项目,然后修改main.xml如“代码清单2-1”所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"> <TextView android:text="red" android:gravity="center_horizontal" android:background="#aa0000" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1"/> <TextView android:text="green" android:gravity="center_horizontal" android:background="#00aa00" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1"/> <TextView android:text="blue" android:gravity="center_horizontal" android:background="#0000aa" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1"/> <TextView android:text="yellow" android:gravity="center_horizontal" android:background="#aaaa00" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1"/> </LinearLayout> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"> <TextView android:text="row one" android:textSize="15pt" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"/> <TextView android:text="row two" android:textSize="15pt" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"/> <TextView android:text="row three" android:textSize="15pt" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"/> <TextView android:text="row four" android:textSize="15pt" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"/> </LinearLayout> </LinearLayout>
代码清单2-1
注意“代码清单2-1”中有两个需要注意的地方,一个是android:orientation这个属性用来描述当前LinearLayout是垂直还是水平,默认不填的话是水平布局,你可以使用“vertical”和“horizontal”来设置。还有一个是XX,这个属性表示权重,我们理解为比例,例如如果A的weight为3,B的weight为1,那么A占整个大小的3/4,B占1/4。“代码清单2-1”这里都是平均分布的,都选的1。然后代码中无需修改任何内容。运行后的效果就如表格2-1中的一样。
2.1.2 Relative Layout
一个RelativeLayout是一个非常强大的工具用来做用户界面,因为它可以消除嵌套ViewGroups。如果你发现自己使用多个嵌套的LinearLayout组,您就可以考虑使用一个RelativeLayout来替换它。下面我们新建一个HelloRelativeLayout项目,然后修改main.xml如“代码清单2-2”所示:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/label" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Type here:"/> <EditText android:id="@+id/entry" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@android:drawable/editbox_background" android:layout_below="@id/label"/> <Button android:id="@+id/ok" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/entry" android:layout_alignParentRight="true" android:layout_marginLeft="10dip" android:text="OK" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@id/ok" android:layout_alignTop="@id/ok" android:text="Cancel" /> </RelativeLayout>
代码清单2-2
这里我们看到一些属性如
android:layout_below,android:layout_toLeftOf,android:layout_alignParentRight。看字面意思应该就很容易明白,并且使用这些属性的时候都需要传一个ID,因为相对布局你需要指定一个与之相对应的对象,它会根据这个对象来调整自己的位置。大家可以多试一下其他的属性,就能明白使用方法了。运行后的效果就如表格2-1中的一样。
2.1.3 Table Layout
TableLayout是基于行和列的布局模式,我们新建一个HelloTableLayout项目,然后修改main.xml如“代码清单2-3”所示:
<?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:stretchColumns="1"> <TableRow> <TextView android:layout_column="1" android:text="Open..." android:padding="3dip" /> <TextView android:text="Ctrl-O" android:gravity="right" android:padding="3dip" /> </TableRow> <TableRow> <TextView android:layout_column="1" android:text="Save..." android:padding="3dip" /> <TextView android:text="Ctrl-S" android:gravity="right" android:padding="3dip" /> </TableRow> <TableRow> <TextView android:layout_column="1" android:text="Save As..." android:padding="3dip" /> <TextView android:text="Ctrl-Shift-S" android:gravity="right" android:padding="3dip" /> </TableRow> <View android:layout_height="2dip" android:background="#FF909090" /> <TableRow> <TextView android:text="X" android:padding="3dip" /> <TextView android:text="Import..." android:padding="3dip" /> </TableRow> <TableRow> <TextView android:text="X" android:padding="3dip" /> <TextView android:text="Export..." android:padding="3dip" /> <TextView android:text="Ctrl-E" android:gravity="right" android:padding="3dip" /> </TableRow> <View android:layout_height="2dip" android:background="#FF909090" /> <TableRow> <TextView android:layout_column="1" android:text="Quit" android:padding="3dip" /> </TableRow> </TableLayout>
代码清单2-3
TableLayout类似于Html的表格结构,你可以认为TableLayout像Html<table>元素,TableRow像Html<tr>元素,但列数你可以自定义。运行后的效果就如表格2-1中的一样。
2.1.4 Grid View
GridView是一个显示二维的并能滚动的ViewGroup。每一个GridView的item使用ListAdapter被自动插入到布局中。本小节将创建一个图像的网格,当其中一个item被选中时会使用toast弹出一个消息用来显示图像的位置。我们按照以下步骤完成这个项目。
1. 创建一个HelloGridView的项目
2. 找一些图片资源,或者使用本例中的图片(光盘资源的此项目中有图片资源,在res/drawable-mdpi/目录下)
3. 修改main.xml如“代码清单2-4”所示:
<?xml version="1.0" encoding="utf-8"?> <GridView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/gridview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:columnWidth="90dp" android:numColumns="auto_fit" android:verticalSpacing="10dp" android:horizontalSpacing="10dp" android:stretchMode="columnWidth" android:gravity="center" />
代码清单2-4
这个GridView将填充全屏,属性的含义就如字面意思一样
4. 打开我们的主类 HelloGridView.java,然就修改代码如“代码清单2-5”所示:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); GridView gridview = (GridView) findViewById(R.id.gridview); gridview.setAdapter(new ImageAdapter(this)); gridview.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { Toast.makeText(HelloGridView.this, "" + position, Toast.LENGTH_SHORT).show(); } }); }
代码清单2-5
当你导入相应的包后这里还是会报错,没有找到ImageAdapter,没关系先放着,等下我们会创建这个类。“代码清单2-5”中首先,我们通过findViewById来在代码中获取XML中的GridView对象,然后使用setAdapter给gridview设置一个适配器,最后由于我们需要监听点击事件,所以需要给gridview设置一个监听器,当然你点击一个item时会弹出一个toast,Toast是Android API中一个很好用的类,他能短暂的弹出一些我们想知道的提示信息。
5.创建ImageAdapter类,让它继承与BaseAdapter,如“代码清单”2-6所示:
public class ImageAdapter extends BaseAdapter { private Context mContext; public ImageAdapter(Context c) { mContext = c; } public int getCount() { return mThumbIds.length; } public Object getItem(int position) { return null; } public long getItemId(int position) { return 0; } // 创建一个ImageView当成一个item被Gird引用 public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView; if (convertView == null) { // 如果convertView不为空(即没有被回收),初始化一些属性 imageView = new ImageView(mContext); imageView.setLayoutParams(new GridView.LayoutParams(85, 85)); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setPadding(8, 8, 8, 8); } else { imageView = (ImageView) convertView; } imageView.setImageResource(mThumbIds[position]); return imageView; } // 引用图片 private Integer[] mThumbIds = { R.drawable.sample_2, R.drawable.sample_3, R.drawable.sample_4, R.drawable.sample_5, R.drawable.sample_6, R.drawable.sample_7, R.drawable.sample_0, R.drawable.sample_1, R.drawable.sample_2, R.drawable.sample_3, R.drawable.sample_4, R.drawable.sample_5, R.drawable.sample_6, R.drawable.sample_7, R.drawable.sample_0, R.drawable.sample_1, R.drawable.sample_2, R.drawable.sample_3, R.drawable.sample_4, R.drawable.sample_5, R.drawable.sample_6, R.drawable.sample_7 }; }
代码清单2-6
首先我们继承自BaseAdapter,就获得了BaseAdapter中的一些方法,然后我们写一个构造函数来传一个context,和一些简单的统计方法getItemId(),getItem()这里先预留接口,暂时用不上。我们主要看看getView()方法,只要你继承自BaseAdapter就必须实现此方法,这个方法为每一个图像创建一个新的View,把它添加到ImageAdapter中,然后给ImageView设置一些属性。
6. 执行这个项目,最后运行后的效果就如表格2-1中的一样。
2.1.5 Tab Layout
要创建这种选项卡式的布局,你需要使用TabHost和TabWidget这两个类。TabHost必须是布局的根节点,其中包含一个TabWidget用来显示标签和一个FrameLayout用来显示内容。关于切换标签显示的内容可以用两种方式表示:一种是使用同一个Activity但切换或改变View,另一种则是直接切换Activity。读者想使用哪种方式完全取决于个人的需求,但笔者建议使用不同的Activity,这样为了扩展大规模的应用和布局,能更好的管理。本小节使用多个Activity来创建Tab Layout。步骤如下:
- 创建一个HelloTabLayout的项目
- 在项目中分别创建三个的Activity:ArtistsActivity,AlbumsActivity,SongsActivity。每个Actvity代表一个单独的标签。然后加入一个TextView用来显示一些简单的信息。如“代码清单2-7”所示:
public class ArtistsActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView textview = new TextView(this); textview.setText("This is the Artists tab"); setContentView(textview); } }
代码清单2-7
这里TextView我们使用代码布局。并且每个Acitivty都一样只是"This is the Artists tab"需要根据不同的Activity稍微调整下。当然别忘了,我们需要在AndroidManifest.xml中为每个Acitivity添加标签。如“代码清单2-8”所示:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.tablayout" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".HelloTabLayout" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".AlbumsActivity" android:theme="@android:style/Theme.NoTitleBar" /> <activity android:name=".ArtistsActivity" android:theme="@android:style/Theme.NoTitleBar" /> <activity android:name=".SongsActivity" android:theme="@android:style/Theme.NoTitleBar" /> </application> </manifest>
代码清单2-8
- 我们需要为每一个选项卡设计Icons。第一大篇的“第6章.用户界面基础指导”中有Icon设计指南的详细描述。这里为了简单快速,我们在光盘资源中使用了比较简单的图片。
(未选中)(选中)
现在我们需要创建一个state-list drawable(后面的Android框架学习中会详细讲述),用来映射一下选中和未选中状态下需要显示的图片。把我们的图片放入res/drawable-mdpi/下,然后创建一个res/drawable/目录,在这个文件夹下创建ic_tab_artists.xml,ic_tab_albums.xml,ic_tab_songs.xml 这3个XML文件,都加入同样的代码,如“代码清单2-9”所示:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 选中时使用灰白 --> <item android:drawable="@drawable/ic_tab_artists_grey" android:state_selected="true" /> <!-- 未选中时使用白色 --> <item android:drawable="@drawable/ic_tab_artists_white" /> </selector>
代码清单2-9
- 修改res/layout/main.xml文件如“代码清单2-10”所示:
<?xml version="1.0" encoding="utf-8"?> <TabHost xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="5dp"> <TabWidget android:id="@android:id/tabs" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="5dp" /> </LinearLayout> </TabHost>
代码清单2-10
- 打开我们的主Acitivty:HelloTabLayout.java让它继承自TabActivity而不是Activity(注意Android3.0以上请使用Fragment,它已经完全取代了TabActivity)。然后修改我们的HelloTabLayout.java中的onCreate()方法,如“代码清单2-11”所示:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Resources res = getResources(); // 获得Drawables资源对象 TabHost tabHost = getTabHost(); // 把我们的主Activity当成TabHost TabHost.TabSpec spec; // 为每一个tab指定可复用的TabSpec Intent intent; // 为每一个tab指定可复用的Intent // 创建一个Intent,用来为每一个tab启动一个Activity(这里的Intent只需要一个对象即可) intent = new Intent().setClass(this, ArtistsActivity.class); // 为每一个tab初始化一个TabSpec然后添加到TabHost中 spec = tabHost.newTabSpec("artists").setIndicator("Artists", res.getDrawable(R.drawable.ic_tab_artists)) .setContent(intent); tabHost.addTab(spec); intent = new Intent().setClass(this, AlbumsActivity.class); spec = tabHost.newTabSpec("albums").setIndicator("Albums", res.getDrawable(R.drawable.ic_tab_albums)) .setContent(intent); tabHost.addTab(spec); intent = new Intent().setClass(this, SongsActivity.class); spec = tabHost.newTabSpec("songs").setIndicator("Songs", res.getDrawable(R.drawable.ic_tab_songs)) .setContent(intent); tabHost.addTab(spec); tabHost.setCurrentTab(2); }
代码清单2-11
为每一个选项卡设置自己的文字和图标和Activity,首先我们通过getTabHost()获得TabHos的引用,然后创建TabHost.TabSpec为每个标签设置属性,最后使用setCurrentTab()来指定打开程序后默认显示的标签位置,我们这里没有使用TabWidget对象,因为当一个标签被添加到TabHost时,它会自动加入到TabHost下的TabWidget中。
- 执行我们的程序,最后运行后的效果就如表格2-1中的一样。
2.1.6 List View
List View也是一个ViewGroup,它用来创建一个可滚动的列表,里面的每一个元素都是一个item。并且和GridView类似它需要一个ListAdapter这样的适配器。本节我们会创建一个ListView,里面显示的是一些国家的名字,这些名字保存在一个String数组中,当一个item被选中时,会弹出一个Toast消息先显示一个这个item在list中的位置信息。创建步骤如下:
1. 创建一个HelloListView的项目
2. 在res/layout/下,创建一个list_item.xml的文件,代码如“代码清单2-12”所示:
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dp" android:textSize="16sp" > </TextView>
代码清单2-12
这个xml文件定义了ListView中每一个item的布局
3. 打开我们的主Activity文件“HelloListView.java”然后修改这个类,让它继承自ListActivity而不是Activity,然后修改其中的onCreate()方法如“代码清单2-13”所示:
static final String[] COUNTRIES = new String[] { "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde", "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo", "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic", "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland", "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia", "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "*", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica", "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova", "Monaco", "*", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas", "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar", "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena", "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal", "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea", "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden", "Switzerland", "Syria", "*", "Tajikistan", "Tanzania", "Thailand", "The Bahamas", "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan", "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara", "Yemen", "Yugoslavia", "Zambia", "Zimbabwe" }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, COUNTRIES)); ListView lv = getListView(); lv.setTextFilterEnabled(true); lv.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // 当点击时,Toast显示文本信息 Toast.makeText(getApplicationContext(), ((TextView) view).getText(), Toast.LENGTH_SHORT).show(); } }); }
代码清单2-13
注意我们这里没有使用setContentView()来载入一个布局,取而代之的是使用setListAdapter(),因为在ListActivity中,只需要使用setListAdapter()即可自动添加ListView在屏幕中。然后在setListAdapter()中我们new了一个ArrayAdapter,这是Android已经写好的一个类,我们可以直接使用,传入一个Context和一个item布局的xml文件,最后在传入一个字符数组COUNTEIES。setTextFilterEnabled(boolean)这个方法表示在ListView中过滤文本,当用户开始打字时,这个listView会被过滤。后面我们设置了一个监听,当你点击ListView中的某个item时的响应代码就是此处。这里我们是试用Toast弹出一个显示信息。如果你用模拟器的话,可以在键盘上输入过滤字符,如图2-1所示:
4.运行程序,如果你用模拟器的话,可以在键盘上输入过滤字符,运行后的截图就如表格1中的一样,它会自动定位到匹配的item字段:
下面我们开始换一种字符串的处理方式,这种把字符串写到代码中的硬编码方式,我们要放弃它,更好的方法是在strings.xml中引用<string-array>节点。例如“代码清单2-14”所示:
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="countries_array"> <item>Bahrain</item> <item>Bangladesh</item> <item>Barbados</item> <item>Belarus</item> <item>Belgium</item> <item>Belize</item> <item>Benin</item> </string-array> </resources>
代码清单2-14
修改我们调用的地方,如“代码清单2-15”所示:
String[] countries = getResources().getStringArray(R.array.countries_array); setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, countries));
代码清单2-15
完整项目下载地址:http://url.cn/PWdcn3
本文来自jy02432443,QQ78117253。转载请保留出处,并保留追究法律责任的权利