我们初学者在刚开始学习Android时,通常都是往上罗列控件,但实际上我们有很多的布局方式,通过这些布局我们可以让我们的App更加优美,同时可以帮助我们适配不同分辨率的机型。在Android中,常见的布局有五种:
l LinearLayout(线性布局)
l RelativeLayout(相对布局)
l FrameLayout(帧布局或框架布局)
l AbsoluteLayout(绝对布局)
l TableLayout(表格布局)
其中前三个布局在日常中最常使用,剩下的两个布局很少用到。
线性布局:顾名思义就是像一条线一样排列,谁先来就在谁的前面;其中,重要的属性:
其中,vertical是垂直排列属性(从上到下排列),horizontal水平排列属性;(从左到右排列);另一重要的特点,在线性布局中,子控件有Layout_weight属性,Layout_weight是水平所占比重
如果我们想让两个TextView各占这个屏幕的一半,我们可以用layout_weight属性;
此时,我们可以看到TextView的宽度各占一半。
相对布局:就是该控件相对于其他控件的位置。相对布局提供了非常灵活的布局方式,允许根据父元素或其他视图的位置定义每个元素在布局中的位置。其中,后定义的控件默认会盖住前面的控件(类似于z轴)。
相对布局的属性非常多,而且都非常常用,相对布局常用属性介绍
这里将这些属性分成组,便于理解和记忆:
1) 属性值为true或false
android:layout_centerHrizontal |
水平居中 |
android:layout_centerVertical |
垂直居中 |
android:layout_centerInparent |
相对于父元素完全居中 |
android:layout_alignParentBottom |
贴紧父元素的下边缘 |
android:layout_alignParentLeft |
贴紧父元素的左边缘 |
android:layout_alignParentRight |
贴紧父元素的右边缘 |
android:layout_alignParentTop |
贴紧父元素的上边缘 |
2) 属性值必须为id的引用名“@id/id-name”
android:layout_below |
在某元素的下方 |
android:layout_above |
在某元素的的上方 |
android:layout_toLeftOf |
在某元素的左边 |
android:layout_toRightOf |
在某元素的右边 |
android:layout_alignTop |
本元素的上边缘和某元素的的上边缘对齐 |
android:layout_alignLeft |
本元素的左边缘和某元素的的左边缘对齐 |
android:layout_alignBottom |
本元素的下边缘和某元素的的下边缘对齐 |
android:layout_alignRight |
本元素的右边缘和某元素的的右边缘对齐 |
3) 属性值为具体的像素值,如30dip,40px
android:layout_marginBottom |
离某元素底边缘的距离 |
android:layout_marginLeft |
离某元素左边缘的距离 |
android:layout_marginRight |
离某元素右边缘的距离 |
android:layout_marginTop |
离某元素上边缘的距离 |
我们可以通过组合这些属性来实现各种各样的布局。
帧布局:是最简单的布局了。所有放在布局里的控件,都按照层次堆叠在屏幕的左上角。后加进来的控件覆盖前面的控件,定义任何空间的位置相关的属性都毫无意义。
绝对布局:指的是指定组件的左上角绝对坐标来指定组件的布局。通过layout_x和layout_y来定义控件在屏幕的位置,这种布局在Android中不常使用,因为android屏幕分布率太多。
表格布局:表格布局模型以行列的形式管理子控件,每一行为一个TableRow的对象,当然也可以是一个View的对象。TableRow可以添加子控件,每添加一个为一列。因为在平常不常用,有兴趣大家可以自行百度哈!
我们知道布局是可以嵌套的,但是过多的布局层次嵌套可能会影响并产生程序的性能问题,所以我们要尽可能减少布局层次。Google官方建议布局层次最多10层,这就要求我们要熟练掌握相对布局,相对布局非常灵活,我们可以一层相对布局可以替代多层的其他布局。
和布局有关的还有一些重要的标签,<include/>,<merge/>,<ViewStub/>等。
<include/>:可以引用相同的布局设计。在一个项目中我们难免会遇到要使用相同的布局格式,但是重复的代码会使我们的文件显得很冗余,我们可以把相同的布局代码单独写成一个模块,然后用的时候可以通过<include/>标签来重用,使用layout="@layout/child_layout"就可以了。但是在引用include标签会有很多注意事项:
1. Include可以使用layout属性来设置布局文件的宽高和位置,但需要注意的是:必须要复写android:layoutwidth和android:layoutheight属性才能使用其它属性(比如:android:layoutgrivity、android:layoutalign...、android:id等)
2. 建议将给include标签调用布局设置宽高、位置、ID等属性放在调用布局的根标签中。
<merge/>:会减少视图的层级。通常用在假如需要在LinearLayout里面嵌入一个布局(或者视图),而恰恰这个布局(或者视图)的根节点也是LinearLayout,这样就多了一层没有用的嵌套,无疑这样只会拖慢程序速度。而这个时候如果我们使用merge根标签就可以避免那样的问题。
<viewstub>:需要时才加载。里面的一些视图先进行预加载,使用的时候在加载,也可以帮助我们优化性能。
有一些小技巧也可以帮助我们进行优化布局,不要嵌套多个使用layout_weight属性的LinearLayout,其次,还可以借助Android lint(帮你删除无用的资源)和Hierarchy View(帮分析所有的层级和怎么进行优化)工具等等。
总之,我们要进行优化布局,就是要减少布局的层次,删除无用的布局,布局结构要清晰,还有选择合适的布局。
Listview可以算是android中非常重要的控件,ListView里面的每个子项Item可以使一个字符串,也可以是一个组合控件。
ListView的显示需要三个元素:
1. ListVeiw用来展示列表的View。
2.适配器 用来把数据绑定到ListView。
3.数据 具体的将被映射的字符串,图片,或者基本组件。
我们通过一个模仿通讯录例子来说明ListView的相关属性;
1) 创建listview标签
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="通讯录"/>
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</LinearLayout>
2) 创建适配器类(PhoneBook_Adapter.java)
importandroid.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import java.util.ArrayList; import java.util.List; public class PhoneBook_Adapter extends BaseAdapter { private Contextcontext;//上下文 private LayoutInflater mLayoutinflater;//解析layout,把布局读出来 private List<UserInfo> mUserInfo=new ArrayList<>();//把对象作为适配器的数据源 public PhoneBook_Adapter(Context context,List<UserInfo> userInfos) { this.context = context; mLayoutinflater= (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mUserInfo=userInfos; } @Override public int getCount() { //有多少个数据 return mUserInfo.size(); } @Override public Object getItem(int i) { //返回某一条的数据对象 return mUserInfo.get(i); } @Override public long getItemId(int i) { return i; } //getView是让每一行数据显示在界面,用户能够看到的 @Override public View getView(int i, View view, ViewGroup viewGroup) { //返回一个视图,i是它的位置,view指的是这个视图,viewGroup是属于哪个ViewGroup ViewHolder viewHolder; if(view==null) { view = mLayoutinflater.inflate(R.layout.item_phone_book, null);//把这个布局读出来 viewHolder=new ViewHolder(); viewHolder.name= (TextView) view.findViewById(R.id.text_name);//从布局中找到TextView viewHolder.age=(TextView)view.findViewById(R.id.text_age); viewHolder.imageView=(ImageView)view.findViewById(R.id.image); view.setTag(viewHolder); } else{ viewHolder= (ViewHolder) view.getTag(); } viewHolder.name.setText(mUserInfo.get(i).getUsername()); //和数据之间进行绑定 viewHolder.age. setText(mUserInfo.get(i).getAge()+" "); viewHolder.imageView.setImageResource(R.mipmap.ic_launcher); return view; } public void refreshData(List<UserInfo> userInfos){ mUserInfo=userInfos;//把旧的列表指向新的列表 notifyDataSetChanged();//列表刷新数据 } } class ViewHolder{ TextView name; TextView age; ImageView imageView; }
UserInfo.java(ListView里面的Item的类)
importjava.io.Serializable; public class UserInfo implements Serializable{ private String username; private int age; public UserInfo(String username, int age) { this.username = username; this.age = age; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
3) List_View.java
import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.Toast; import java.util.ArrayList; import java.util.List; public class List_View extends Activity{ private ListView phoneBook; private List<UserInfo> userInfos; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_listview); phoneBook=(ListView)findViewById(R.id.list_view); userInfos = new ArrayList<>(); userInfos.add(new UserInfo("one",21)); userInfos.add(new UserInfo("two",30)); userInfos.add(new UserInfo("three",49)); userInfos.add(new UserInfo("four",28)); userInfos.add(new UserInfo("four",28)); userInfos.add(new UserInfo("four",28)); userInfos.add(new UserInfo("four",28)); userInfos.add(new UserInfo("four",28)); userInfos.add(new UserInfo("four",28)); userInfos.add(new UserInfo("one",21)); userInfos.add(new UserInfo("two",30)); userInfos.add(new UserInfo("three",49)); userInfos.add(new UserInfo("four",28)); userInfos.add(new UserInfo("four",28)); userInfos.add(new UserInfo("four",28)); userInfos.add(new UserInfo("four",28)); userInfos.add(new UserInfo("four",28)); userInfos.add(new UserInfo("four",28)); final PhoneBook_Adapter phoneBook_adapter=new PhoneBook_Adapter(List_View.this, userInfos); phoneBook.setAdapter(phoneBook_adapter);//将列表与内容进行绑定,adapter是适配器 phoneBook_adapter.notifyDataSetChanged();//通知数据被改变了,数据是和Adapter相关联的 phoneBook.setOnItemClickListener(new AdapterView.OnItemClickListener() {//元素被点击 @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { //i是点击的位置,即position,view是视图 if(i==0){ //新建一批新的数据 //替换掉旧的数据 //刷新listview,更新自己的视图 userInfos.clear(); userInfos.add(new UserInfo("我是新的数据1",1)); userInfos.add(new UserInfo("我是新的数据2",2)); userInfos.add(new UserInfo("我是新的数据3",3)); userInfos.add(new UserInfo("我是新的数据4",4)); phoneBook_adapter.refreshData(userInfos); } Toast.makeText(List_View.this,userInfos.get(i).getUsername(),Toast.LENGTH_SHORT).show(); } });
}
}
至于xml文件,都是一些很简单的控件;
Activity_listview.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="通讯录"/> <ListView android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="match_parent" android:fastScrollEnabled="true"></ListView> </LinearLayout>
Item_phone_book.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/image" android:layout_width="48dp" android:layout_height="48dp" android:src="@mipmap/ic_launcher"/> <TextView android:id="@+id/text_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_toRightOf="@+id/image" android:text=""/> <TextView android:id="@+id/text_age" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/text_name" android:layout_toRightOf="@+id/image" android:text=""/> </RelativeLayout>
然后我们就可以试着运行一下我们的程序啦!
除了上面所提到的一些方法以外,ListVie还有listSelectorscrollingCache,cacheColorHint,fastScrollEnabled等常用属性,addHeaderView和addFooterview方法分别是下拉刷新,上拉加载更多的实现方法。大家在下面可以自己更加深入的学习;
GridView和ListView没有太大区别,同样也是要借助适配器来实现数据和View的绑定。但是GridView在布局上有些特殊的属性,比如:
android:numColumn=”3”(显示三列,也可以是auto_fit自动适应)
android:columnWidth(每列的宽度)
android:verticalSpacing(垂直边距)
android:horizontalSpacing(水平边距)
ScrollView:当内容超过了整个屏幕或者容器的时候需要使用ScrollView,并且ScrollView的直接子元素只能有一个,若有多个的话系统会报错。ScrollView只支持垂直滚动,,若要支持水平滚动,则要使用HorizontalScrollView。
以上就是我第二章学习笔记,个人能力有限,难免有些不足,请大家多多包涵。