Android开发之鬼迷心窍(二)

学习笔记(二)

布局与优化

我们初学者在刚开始学习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:layoutwidthandroid:layoutheight属性才能使用其它属性(比如:android:layoutgrivity、android:layoutalign...、android:id等)

2.        建议将给include标签调用布局设置宽高、位置、ID等属性放在调用布局的根标签中。

 

<merge/>:会减少视图的层级。通常用在假如需要在LinearLayout里面嵌入一个布局(或者视图),而恰恰这个布局(或者视图)的根节点也是LinearLayout,这样就多了一层没有用的嵌套,无疑这样只会拖慢程序速度。而这个时候如果我们使用merge根标签就可以避免那样的问题。

 

<viewstub>:需要时才加载。里面的一些视图先进行预加载,使用的时候在加载,也可以帮助我们优化性能。

 

  有一些小技巧也可以帮助我们进行优化布局,不要嵌套多个使用layout_weight属性的LinearLayout,其次,还可以借助Android lint(帮你删除无用的资源)和Hierarchy View(帮分析所有的层级和怎么进行优化)工具等等。

 

  总之,我们要进行优化布局,就是要减少布局的层次,删除无用的布局,布局结构要清晰,还有选择合适的布局。

 

无比重要的ListView

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和ScrollView

GridView和ListView没有太大区别,同样也是要借助适配器来实现数据和View的绑定。但是GridView在布局上有些特殊的属性,比如:

android:numColumn=”3”(显示三列,也可以是auto_fit自动适应)

android:columnWidth(每列的宽度)

android:verticalSpacing(垂直边距)

android:horizontalSpacing(水平边距)

 

ScrollView:当内容超过了整个屏幕或者容器的时候需要使用ScrollView,并且ScrollView的直接子元素只能有一个,若有多个的话系统会报错。ScrollView只支持垂直滚动,,若要支持水平滚动,则要使用HorizontalScrollView。

 

以上就是我第二章学习笔记,个人能力有限,难免有些不足,请大家多多包涵。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值