第三章UI
一、常用控件
1、TextView
2、Button
3、EditText
密码:android:password=”true”
4、ImageView
5、ProgressBar
设置其进度
progress=bar.getProgress();
progress+=10;
bar.setProgress(progress);
if(progress==100)
{
bar.setVisibility(View.GONE);
}
6、AlertDialog
AlertDialog.Builder dialog=new AlertDialog.Builder(MainActivity.this);
dialog.setTitle("确认删除");
dialog.setMessage("你确认删除么?");
dialog.setCancelable(false);
dialog.setPositiveButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "已经删除", Toast.LENGTH_SHORT).show();
}
});
dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "已经取消", Toast.LENGTH_SHORT).show();
}
});
dialog.show();
7、ProgressDialog
和AlertDialog类似,只是内容为一个进度条。
进度加载完成之后,必须使用dismiss()来关闭对话框。
二、基本布局
1、LinearLayout
android:gravity指定文字在控件中的对齐方式
android:layout_gravity:指定控件在布局中的对齐方式
android:layout_weight:按比例分配控件大小
2、RelativeLayout
3、FrameLayout
4、TableLayout
android:layout_span=”2”将两列合并为一列
在TableRow中无法指定控件的宽度,通过android:stretchColumns=”1”,指定将第二列拉伸到最大。
5、GridLayout
三、自定义控件
Android中,控件和布局的继承结构图
1、添加自定义标题布局
自定义一个布局title.xml,然后在mainactivity布局中引入
当然,需要将系统自带标题栏屏蔽
requestWindowFeature(Window.FEATURE_NO_TITLE);
2、创建自定义控件
上面方法自定义的标题栏并不能响应操作,采用自定义控件方法来实现操作。
(1)首先,构建一个title.xml布局文件
(2)然后,构建一个自定义标题控件TitleLayout:
利用LayoutInflater动态加载布局文件title.xml。
public class TitleLayout extends LinearLayout{
public TitleLayout( Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title, this);
Button edit=(Button) findViewById(R.id.title_edit);
Button back=(Button) findViewById(R.id.title_back);
edit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getContext(), "Edit", Toast.LENGTH_SHORT).show();
}
});
back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getContext(), "Back", Toast.LENGTH_SHORT).show();
}
});
}
}
(3)如同加入其它的控件一样,将该自定义的控件添加到mainactivity.xml文件中
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
四、ListView
1、最简单的Adapter
要将数据放置在ListView中,都需要一个adapter转换。
一个最简单的adapter,就是把一个字符串数组放置在ListView中。
ArrayAdapter接收3个参数:context,ListView单个子项布局id和数据。
listView=(ListView) findViewById(R.id.listView1);
ArrayAdapter adapter=new ArrayAdapter(MainActivity.this,
android.R.layout.simple_list_item_1, data);
listView.setAdapter(adapter);
2、定制ListView界面
只显示文字很单调,需要显示图片等,则需要构建自定义的布局。
(1)数据:Fruit类
首先准备需要适配的数据,数据包括文字、图片id,定义一个Fruit类存放这些数据。
(2)子项布局:fruit_layout.xml
之后,需要自定义ListView中单个子项的布局。本例中就是一个图片加上一个文字。
(3)自定义适配器:FruitAdapter.java
该适配器中,最重要的是getView()方法。该方法在每个子项滚动到屏幕内时被调用。
position是该子项的位置,利用getItem(position)可以获得当前的Fruit实例fruit;
然后,利用LayoutInflater可以加载布局为fruit_layout的布局view;
该布局view即为步骤(2)中自定义的布局,通过view.findViewById()可以获得ImageView和TextView。
最后,将fruit中的imageId和name传入ImageView和TextView。
public class FruitAdapter extends ArrayAdapter{
private int resourceId;
public FruitAdapter(Context context, int resource, List objects) {
super(context, resource, objects);
resourceId=resource;
}
public View getView(int position, View convertView, ViewGroup parent) {
Fruit fruit=getItem(position);
View view=LayoutInflater.from(getContext()).inflate(R.layout.fruit_layout, null);
TextView fruit_name=(TextView) view.findViewById(R.id.fruit_name);
ImageView fruit_image=(ImageView) view.findViewById(R.id.fruit_image);
fruit_image.setImageResource(fruit.getImageId());
fruit_name.setText(fruit.getName());
return view;
}
}
(4)使用
List fruits=new ArrayList();
FruitAdapter adapter=new FruitAdapter(MainActivity.this, R.layout.fruit_layout, fruits);
在fruits中添加数据。
3、提升ListView效率
getView()每次都将布局重新加载一遍,效率很低。处理方法为:
(1)convertView
convertView将之前加载好的布局进行缓存,以便之后重用。则可以不必每次都使用LayoutInflater重新加载布局,而直接加载缓存的布局。
if(convertView==null) view=LayoutInflater.from(getContext()).inflate(R.layout.fruit_layout, null);
else
view=convertView;
(2)ViewHolder
每次都使用findViewById获取控件,效率低下。
使用convertView将之前已经find的view也一起缓存。
View有setTag()和getTag()方法,分别进行数据写入和读取。
采用自定义的ViewHolder类,将多个参数一起管理,比如TextView/ImageView等。
public class FruitAdapter extends ArrayAdapter {
public FruitAdapter(Context context, int resource, List objects) {
super(context, resource, objects);
resourceId = resource;
}
private int resourceId;
public View getView(int position, View convertView, ViewGroup parent) {
Fruit fruit = getItem(position);
View view;
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder(); //一定要记住实例化对象啊
view = LayoutInflater.from(getContext()).inflate(
R.layout.fruit_layout, null);
viewHolder.fruit_image = (ImageView) view
.findViewById(R.id.fruit_image);
viewHolder.fruit_name=(TextView) view.findViewById(R.id.fruit_name);
view.setTag(viewHolder);
} else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.fruit_image.setImageResource(fruit.getImageId());
viewHolder.fruit_name.setText(fruit.getName());
return view;
}
class ViewHolder {
ImageView fruit_image;
TextView fruit_name;
}
}
4、ListView点击事件
注册setOnItemClickListener()事件:
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View view,
int position, long id) {
Fruit fruit=fruits.get(position);
Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
五、单位和尺寸
px:像素
pt:磅数,1pt=1/72inch
dp:密度无关像素
密度dpi:屏幕每inch包含的像素数。
获取当前屏幕密度值:
float xdpi=getResources().getDisplayMetrics().xdpi;
float ydpi=getResources().getDisplayMetrics().ydpi;
sp:可伸缩像素。
规定,在160dpi屏幕上,1dp=1px;在320dpi屏幕上,1dp=2px.
六、最佳实践——聊天界面
APP: ChatWe
新内容有:
当有新内容时,刷新ListView中的显示:adapter.notifyDataSetChanged();
将ListView定位到最后一行:listView.setSelection(messages.size());
指定ListView中分割线为透明:android:divider=”#0000”