Android学习笔记(三)UI

3. UI界面

3.1 常见控件

3.1.1 TextView

显示一段文本信息。默认左上角对齐。
属性 释义
android:layout_width 宽度(所有控件都有) match_parent:当前控件大小与父布局一致
fill_parent:同match_parent一样,官方推荐match_parent
wrap_content:当前控件大小正好能包含内容(由内容来决定)
android:layout_height 高度 (所有控件都有) 同上
android:gravity 文字对齐方式 top、bottom、left、right、center等 , 可 以 用 “ | ” 来 同 时 指 定 多 个 值
android:textSize 文字大小 -
android:textColor 文字颜色 -

3.1.2 Button

按钮

3.1.3 EditText

输入框控件
属性 释义
android:hint 输入框的提示信息(相当于H5的placeholder) -
android:maxLines 指定最大行数 数字

3.1.4 ImageView

展示图片控件

属性 释义
android:src 指定图片 -
通过以下代码来动态的为图片控件指定图片资源:
imageView.setImageResource(R.drawable.test);

3.1.5 ProgressBar

进度条

属性 释义
android:visibility 控件是否可见(所有控件都有) visible:可见,默认值
invisible:不可见,但仍然占据原来的位置和大小(可理解为透明)
gone:不仅不可见,而且不占用原有任何空间
android:max 在给进度条添加如下属性的时候:
style="?android:attr/progressBarStyleHorizontal",
该进度条就成了一个水平进度条。
此时设置此max属性表示最大值为多少,比如100
-
//设置可见性,还有View.GONE、View.INVISIBLE
progressBar.setVisibility(View.VISIBLE);
//设置进度
progressBar.setProgress(60);

3.1.6 AlertDialog

对话框,置顶于所有控件之上,屏蔽他们的交互能力。
/**
 * 1.首先通过AlertDialog.Builder来创建一个AlertDialog实例
 * 2.然后设置标题、内容、可否取消等属性
 * 3. setPositiveButton()方法为对话框确定按钮设置文本以及事件
 * 4. setNegativeButton()方法则为取消按钮设置文本及事件
 */
AlertDialog.Builder dialog=new AlertDialog.Builder(MainActivity.this);
dialog.setTitle("This is a dialog");
dialog.setMessage("Some thing want to show");
dialog.setCancelable(false);
dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {

    }
});
dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {

    }
});
dialog.show();

3.1.7 ProgressDialog

对话框进度条
/**
 * 1.先创建一个ProgressDialog对象
 * 2.同样设置标题、内容、是否可取消
 * 3.设置setCancelable(false)后则不能按Back键关闭对话框
 */
ProgressDialog dialog=new ProgressDialog(MainActivity.this);
dialog.setTitle("This is a progress dialog");
dialog.setMessage("Please Loading ....");
dialog.setCancelable(false);
dialog.show();
//可以调用此方法来关闭对话框
//dialog.dismiss();

3.2 基本布局

Android学习笔记(三)UI_第1张图片

3.2.1 线性布局(LinearLayout)

将所有其包含的控件在线性方向上依次排列,是一种非常常用的布局。
属性 释义
android:orientation 线性排列方向 horizontal(水平方向)、vertical(垂直方向)
android:layout_gravity 控件在布局中的对齐方式 注意:当布局方向为horizontal时,只有垂直方向的对齐方式起作用
同理,当为vertical时,只有水平方向的起作用。
android:layout_weight 使用比例来指定控件大小 比如一共有2个控件,一个设为3,另一个设为2,则第一个占3/5,第二个占2/5;
同理如果两个都想占一半,则每个设为1即可,即1/2

3.2.2 相对布局(RelativeLayout)

相对布局更加随意,通过相对定位的方式让控件出现在布局的任何位置。因此相对布局属性非常多,但有规律可循。

属性 释义
android:layout_alignParentLeft 相对父布局向左 true、false
android:layout_alignParentTop 相对父布局向上 true、false
android:layout_alignParentRight 相对父布局向右 true、false
android:layout_alignParentBottom 相对父布局向下 true、false
android:layout_centerInParent 相对父布局居中 true、false
android:layout_above 让控件位于另一个控件上方,注意!该控件需要定义在另一个控件
后面,下同
需要指定参考的控件id引用,如:@id/button1
android:layout_below 让控件位于另一个控件下方 同上
android:layout_toLeftOf 让控件位于另一个控件左侧 同上
android:layout_toRightOf 让控件位于另一个控件右侧 同上
android:layout_alignLeft 让控件左边缘和另一个控件左边缘对齐 控件id的引用
android:layout_alignRight 让控件右边缘和另一个控件右边缘对齐 同上
android:layout_alignTop 让控件上边缘和另一个控件上边缘对齐 同上
android:layout_alignBottom 让控件下边缘和另一个控件下边缘对齐 同上

3.2.3 FrameLayout

这种布局没有任何的定位方式,所有的控件都会摆放在布局的左上角。

3.2.4 TableLayout

使用表格的方式来排列控件。
TableRow:一个标签代表一行,而在一行中的每一个控件都代表一列。但是在TableRow中无法指定控件的宽度,所以可能不会完全利用屏幕的宽度。
android:stretchColumns(属于布局的属性):将TableLayout中的某一列进行拉伸,以达到自动适应屏幕宽度的目的。指定0,表示将第1列拉伸,指定1表示将第2列拉伸。

3.3 自定义控件

Android学习笔记(三)UI_第2张图片


所以控件都直接或间接的继承View;所以布局都直接或间接的继承ViewGroup。

3.3.1 引入布局

(1)新建一个布局title.xml
(2)在主布局文件中添加引用,如下:
(3)别忘了隐藏系统自带的标题栏:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 窗口无标题(别忘了继承自Activity才起作用)
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
}

3.3.2 创建自定义控件

         当一些布局中的控件要求能够响应事件时,比如标题栏的返回按钮,不管在哪个活动中,返回按钮的作用都是销毁当前活动,如果在每一个活动中都注册相同的事件,则又增加了冗余代码,此时自定义控件可以解决此问题。
(1)创建一个自定义控件布局类(这里还是使用标题栏TitleLayout),继承自LinearLayout类
package com.jastar.uicustomviews.layout;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;

import com.jastar.uicustomviews.R;

public class TitleLayout extends LinearLayout {

    /**
     * 重写带有两个参数的构造函数,在布局中引入TitleLayout就会调用这个函数
     *
     * @param context
     * @param attrs
     */
    public TitleLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        /**
         * 1.通过LayoutInflater.from()方法构造一个LayoutInflater对象
         * 2.通过该对象的inflate()来动态加载title.xml布局
         * 3.inflater(要加载的布局文件id,给加载好的布局再指定一个父布局这里使用TitleLayout)
         */
        LayoutInflater.from(context).inflate(R.layout.title, this);
    }
}

(2)在布局文件中添加这个自定义控件
添加自定义控件和添加普通控件方式一样,只不过需要指定完整类名
(3)给按钮添加点击事件
public TitleLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    /**
     * 1.通过LayoutInflater.from()方法构造一个LayoutInflater对象
     * 2.通过该对象的inflate()来动态加载title.xml布局
     * 3.inflater(要加载的布局文件id,给加载好的布局再指定一个父布局这里使用TitleLayout)
     */
    LayoutInflater.from(context).inflate(R.layout.title, this);

    //同样获取到按钮对象
    Button btnBack = (Button) this.findViewById(R.id.title_back);
    Button btnEdit = (Button) this.findViewById(R.id.title_edit);
    btnBack.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            //返回按钮销毁当前活动
            ((Activity) getContext()).finish();
        }
    });
    btnEdit.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(getContext(), "您点击了编辑按钮", Toast.LENGTH_SHORT).show();
        }
    });
}
这样的话,每当引入该布局文件,返回按钮和编辑按钮的事件已经写好,将被共用。

3.4 ListView控件(很常用)

3.4.1 简单使用

(1)在布局中添加ListView控件并指定id为list_view,宽高设为match_parent
(2)在代码中使用:
package com.jastar.listviewtest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends AppCompatActivity {
    /**
     * ListView的数据是需要提前准备好的,无论是从数据库读的还是从哪里来的;这里模拟一些数据
     */
    private String[] data = {"Apple", "Banana", "Orange", "Watermelon", "Pear", "Grap", "Pineapple", "Strawberry", "Cherry", "Mango"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /**
         * 1.Android中的数组是无法直接传递给ListView的,需要借助适配器Adapter来实现
         * 2.ArrayAdapter还算是比较好用的,可以指定泛型
         * 3.构造函数需要参数,不同场景应该使用不同的构造函数,此处的参数依次为:
         * param1:当前上下文
         * param2:ListView子项布局id,这是一个安卓内置的子项布局文件,里面只有一个TextView,简单显示文本即可
         * param3:要适配的数据
         */
        ArrayAdapter adapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_list_item_1, data);
        ListView listView = (ListView) findViewById(R.id.list_view);
        //调用setAdapter方法,将适配器传入
        listView.setAdapter(adapter);
    }
}
Android学习笔记(三)UI_第3张图片

3.4.2 定制ListView界面

定制ListView界面就是需要我们自定义ListView子项的布局(下面的例子实现列表名称前显示对应图片的功能)
(1)新建Fruit实体类,有两个字段:name(水果名称),imageId(水果对应的图片id)
(2)创建自定义子项布局fruit_item.xml



    

    

(3)创建自定义适配器FruitAdapter类继承自ArrayAdapter类,指定Fruit实体类泛型
package com.jastar.listviewtest.Adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.jastar.listviewtest.Entity.Fruit;

import java.util.List;


public class FruitAdapter extends ArrayAdapter {
    private int resourceId;


    /**
     * 重写父类构造方法,用于将上下文、ListView、子项布局的id和数据都传递进来
     *
     * @param context            上下文
     * @param textViewResourceId 子项布局Id
     * @param objects            数据
     */
    public FruitAdapter(Context context, int textViewResourceId, List objects) {
        super(context, textViewResourceId, objects);
        resourceId = textViewResourceId;
    }

    /**
     * 1.重写getView方法,该方法在每个子项被滚动到屏幕内的时候调用
     *
     * @param position
     * @param convertView
     * @param parent
     * @return
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //通过getItem()获取当前项的实例
        Fruit fruit = getItem(position);
        //使用LayoutInflater将该子项加载到我们传入的布局
        View view = LayoutInflater.from(getContext()).inflate(resourceId, null);
        //获取子项布局中的控件
        ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
        TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);
        fruitImage.setImageResource(fruit.getImageId());
        fruitName.setText(fruit.getName());

        return view;
    }
}
(4)在活动中使用
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //初始化水果数据,模拟假数据
    initFruitList();
    FruitAdapter adapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, fruitList);
    ListView view = (ListView) findViewById(R.id.list_view);
    view.setAdapter(adapter);

}

private void initFruitList() {
    Fruit apple = new Fruit("Apple", R.drawable.fruit_apple_pic);
    fruitList.add(apple);
 //....
}
Android学习笔记(三)UI_第4张图片

3.4.3 提升ListView的运行效率

(1)优化加载布局的次数
在 FruitAdapter的getView()方法中每次都将布局重新加载了一遍,当ListView快速滚动的时候,效率会很低。
其实getView()还有一个参数没用到就是convertView,这个参数用于将之前加载好的布局进行缓存,以便重用。
修改FruitAdapter中的代码:
Android学习笔记(三)UI_第5张图片

(2)优化获取控件实例次数
在getView()方法中每次都会去findViewById()控件实例,可以借助ViewHolder来对这个问题优化。
Android学习笔记(三)UI_第6张图片

3.4.4 ListView点击事件

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //...

    view.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView parent, View view, int position, long id) {
            Fruit fruit = fruitList.get(position);
            Toast.makeText(MainActivity.this, "name:" + fruit.getName() + ",imageid:" + fruit.getImageId(), Toast.LENGTH_SHORT).show();
        }
    });

}
Android学习笔记(三)UI_第7张图片

3.5 单位和尺寸

在布局文件中常用的单位有:px、pt、dp、sp
px:像素
pt:磅数,1磅等于1/72英寸,一般pt作为字体的单位来使用

px和pt在不同的分辨率手机上显示的效果是完全不相同的,所以这两个单位在手机领域上不适用。
因此,谷歌为Android引入了一套新的单位:dp、sp

dp:密度无关像素的意思,也被称作dip,和px相比,它在不同密度的屏幕中的显示比例保持一致。
sp:可伸缩像素的意思,采用了和dp同样的设计理念,解决文字大小适配问题

密度:
        Android 中的密度就是屏幕每英寸所包含的像素数,通常以 dpi为单位。比如一个手机屏幕的宽是 2 英寸长是 3 英寸,如果它的分辨率是 320*480 像素,那这个屏幕的密度就是 160dpi,如果它的分辨率是640*960,那这个屏幕的密度就是 320dpi,因此密度值越高的屏幕显示的效果就越精细。
        根据 Android 的规定,在 160dpi 的屏幕上,1dp 等于 1px,而在 320dpi 的屏幕上,1dp就等于 2px。

3.6 编写界面最佳实践

3.6.1 制作Nine-Patch图片(可拉伸图片)

Nine-Patch图片:是一种被特殊处理过的图片,能够指定哪些区域可以延伸。
比如:
有一张图片:
Android学习笔记(三)UI_第8张图片

当图片宽度不足以填充整个屏幕时,图片就会被均匀拉伸,成这样:
Android学习笔记(三)UI_第9张图片

所以Nine-Patch图片就是为了解决这个问题。
(1)在Android sdk目录tools文件夹下,找到 draw9patch.bat 文件双击打开
(2)点击File→Open 9-patch将图片加载进来,如:
Android学习笔记(三)UI_第10张图片

(3)可以在四周绘制黑线
上边框和左边框的黑线:表示当图片需要拉伸时就拉伸黑线部分的区域
有边框和下边框的黑线:可画可不画,表示内容绘制区域,说白了就是当有内容放置的时候只放到此区域内。
(4)点击导航File→Save 9-patch,就会生成一个特殊的后缀为“.9.png”的图片。


你可能感兴趣的:(#,Android学习笔记)