zoukankan      html  css  js  c++  java
  • android常用控件和布局

    新建一个UIWidgetDemo来测试Android中的控件和布局。

    控件

    TextView

      android中所有控件都有android:layout_width和android:layout_height这两个属性。这两个属性的可选值有3个:match_parent,fill_parent和wrap_parent。其中,match_parent和fill_parent意义相同,官方更推荐使用match_parent。

    <?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">
    
        <!-- gravity属性为文字的对齐方式,可选值有top,bottom,left,right和center,可以使用'|'来分隔多个值 -->
        <TextView
        android:id="@+id/text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="#00FFEA"
        android:gravity="center"
        android:textSize="24sp"
        android:text="This is a TextView!" />
    </LinearLayout>
    

    image.png

    Button

      默认情况下,系统会将button内的英文自动转换为大写,如果这不是你想要的效果,可以将textAllCaps属性设为false。

    <?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">
    
    	<Button
    		android:id="@+id/button"
    		android:layout_width="match_parent"
    		android:layout_height="wrap_content"
    		android:text="I am a button."
    		android:textAllCaps="false"
    		android:textColor="#ff0000" />
    
    </LinearLayout>
    

    image.png

    可以为button控件的点击事件注册一个监听器:

    import android.view.View;
    import android.widget.Button;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button button = (Button)findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(MainActivity.this, "You clicked the button", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
    
    

    image

      当然了,如果觉得使用匿名内部类的方式来注册监听器不是很直观,也可以使用实现View.OnClickListener接口的方法来注册事件监听。

    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button button = (Button) findViewById(R.id.button);
            button.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.button:
                    Toast.makeText(MainActivity.this, "You clicked the button", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    break;
            }
        }
    }
    

    image.png

    EditText

    <?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">
    
        <!-- hint表示输入框中的一段提示性文本 -->
        <EditText
            android:id="@+id/edit_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Type something here!"
            android:maxLines="2" />
        <!-- maxLines表示输入框中可向下拓展的最大行数,超过这个行数则会产生滚动 -->
    </LinearLayout>
    

    image.png

    可以结合按钮和输入框来做一些事情:

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private EditText editText;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button button = (Button) findViewById(R.id.button);
            editText = (EditText) findViewById(R.id.edit_text);
            button.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch(v.getId()) {
                case R.id.button:
                    // 在按钮的点击事件处理函数中得到输入框的输入并以toast的形式显示出来
                    String inputText = editText.getText().toString();
                    Toast.makeText(MainActivity.this, inputText, Toast.LENGTH_SHORT).show();
                    break;
                default:
                    break;
            }
        }
    }
    

    image

    ImageView

    <?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">
    
            <ImageView
                android:id="@+id/img1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/img_1" />
    
            <Button
                android:id="@+id/button"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="I am a button."
                android:textAllCaps="false"
                android:textColor="#ff0000" />
    
    </LinearLayout>
    

    image.png

    可以在程序中通过代码动态的更改ImageView中的图片,修改MainActivity的代码:

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private ImageView img1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button button = (Button) findViewById(R.id.button);
            img1  = (ImageView) findViewById(R.id.img1);
            button.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch(v.getId()) {
                case R.id.button:
                    // 点击按钮后改变图片
                    img1.setImageResource(R.drawable.img_2);
                    break;
                default:
                    break;
            }
        }
    }
    

    image

    ProgressBar

    <?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">
    
            <Button
                android:id="@+id/button"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="I am button."
                android:textAllCaps="false"
                android:textColor="#ff0000" />
    
            <ProgressBar
                android:id="@+id/progress_bar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
    
    </LinearLayout>
    

    image

      这时我们可能会注意到一个问题,旋转的进度条表示程序正在加载数据,而数据总会有加载完的时候,如何让进度条在数据加载完成后就消失呢?

      这就需要用到android:visibility控件可见属性进行指定,它的可选值有3种:visible,invisible和gone。visible表示控件是可见的,是默认值;invisible表示控件不可见,但它仍然会占据着原来的位置,可以理解为控件变为全透明状态了;gone则表示控件不仅不可见,而且不会在占用任何屏幕控件。

      除了可以直接设置控件的xml属性android:visibility来指定控件的可见性,还可以在代码中使用setVisibility()方法指定控件的可见与否,可以向它传入View.VISIBLE,View.INVISIBLE和View.GONE这3个值。

    接下来我们就来实现当数据加载完成后进度条消失的效果:

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private Button button;
        private ProgressBar progressBar;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            button = (Button) findViewById(R.id.button);
            progressBar = (ProgressBar) findViewById(R.id.progress_bar);
            button.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.button:
                    // 通过getVisibility()来判断当前进度条是否可见
                    if(progressBar.getVisibility() == View.GONE) {
                        progressBar.setVisibility(View.VISIBLE);
                    } else {
                        progressBar.setVisibility(View.GONE);
                    }
                    break;
                default:
                    break;
            }
        }
    }
    

    image

    另外,默认情况下,进度条是圆形样式,可以使用style属性将它指定为水平进度条:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        ...
    
        <ProgressBar
            android:id="@+id/progress_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            style="?android:attr/progressBarStyleHorizontal"
            android:max="100" />
            <!-- 给进度条指定max最大值100 -->
    </LinearLayout>
    

    image.png

    将进度条改为水平进度条后,我们就可以在程序中动态的更新进度条的进度值:

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private Button button;
        private ProgressBar progressBar;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            button = (Button) findViewById(R.id.button);
            progressBar = (ProgressBar) findViewById(R.id.progress_bar);
            button.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.button:
                    // 使用getProgress()获取当前的进度值
                    int progress = progressBar.getProgress();
                    progress = progress + 10;
                    progressBar.setProgress(progress);
                    break;
                default:
                    break;
            }
        }
    }
    

    image

    AlertDialog

      AlertDialog可以在当前的界面中弹出一个对话框,这个对话框是置顶于所有界面元素之上的,能够屏蔽掉其他控件的交互能力(模态窗口)。因此AlertDialog一般用于提示一些非常重要的内容或警告信息。

    下面我们来看看怎么使用AlertDialog控件:

    import android.content.DialogInterface;
    import android.support.v7.app.AlertDialog;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.*;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button button = (Button) findViewById(R.id.button);
            button.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.button:   // 点击事件是由R.id.button发起的
                    // 首先构造一个AlertDialog控件对象
                    AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
                    dialog.setTitle("This is a Dialog");
                    dialog.setMessage("Something important.");
                    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();
                    break;
                default:
                    break;
            }
        }
    }
    

    image

    ProgressDialog

      ProgressDialog和AlertDialog有点类似,都可以在界面上弹出一个对话框并屏蔽其他控件的交互能力。但不同的是,ProgressDialog会在对话框中显示一个进度条,一般用于表示当前操作比较耗时,让用户耐心的等待。

    它的用法和AlertDialog很类似:

    import android.app.ProgressDialog;
    import android.content.DialogInterface;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.*;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button button = (Button) findViewById(R.id.button);
            button.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.button:
                    // 首先构造一个AlertDialog控件对象
                    ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);
                    progressDialog.setTitle("This is a Dialog");
                    progressDialog.setMessage("Something important.");
                    progressDialog.setCancelable(true);     // 允许取消
    
                    progressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                        @Override
                        public void onDismiss(DialogInterface dialog) {
                            Toast.makeText(MainActivity.this, "你点击了取消", Toast.LENGTH_SHORT).show();
                        }
                    });
    
                    // 显示对话框
                    progressDialog.show();
                    break;
                default:
                    break;
            }
        }
    }
    

    image

    ListView

      ListView应该可以算是Android中最常用的控件之一,几乎所有的应用程序都会用到它。

      由于手机屏幕空间是有限的,所以能够一次性在屏幕上显示的内容并不多,当我们的程序中有大量的数据需要展示的时候,就可以借助ListView来实现。

      ListView允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕。事实上,我们几乎每天都在接触这个控件,比如查看QQ聊天记录,翻阅微博最新消息,等等。

    ListView的简单用法

    首先给程序一个布局:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ListView
            android:id="@+id/list_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </LinearLayout>
    

    在xml布局中加入ListView还算简单,下面看一看MainActivity中的代码:

    public class MainActivity extends AppCompatActivity {
        private String[] data = {
            "Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape",
            "Pineapple", "Strawberry", "Cherry", "Mango", 
            "Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape",
            "Pineapple", "Strawberry", "Cherry", "Mango"
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            // 定义一个数组适配器adapter(上述数组中的元素都是字符串)
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, data);
            // 使用android.R.layout.simple_list_item_1, data作为ListView子项布局的id,这是一个Android内置的布局文件,里面只有一个TextView,可用于简单地显示一段文本
            ListView listView = (ListView) findViewById(R.id.list_view);
            // listView应用这个适配器
            listView.setAdapter(adapter);
        }
    }
    

      ListView中的展示数据可以是从数据库中读取出来的,也可以是从网上下载下来的,这里我们就简单使用一个data数组来测试。

    image

    定制ListView界面

    只能显示一段文本的ListView实在是太单调了,我们可以对ListView做一些个性化的定制。

    下面的例子中,我们要在每个列表项前面加上一张图片。

    首先创建一个实体类,作为ListView适配器的适配类型。新建类Fruit:

    public class Fruit {
        private String name;    // 水果的名称
        private int imageId;    // 对应的图片的资源id
    
        public Fruit(String name, int imageId) {
            this.name = name;
            this.imageId = imageId;
        }
    
        public String getName() {
            return name;
        }
    
        public int getImageId() {
            return imageId;
        }
    }
    

    然后需要为ListView子项指定一个我们自定义的布局,新建fruit_item.xml:

    <?xml version="1.0" encoding="utf-8" ?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <!--
        ListView中的每一项都对应有一个固定的布局文件,前面我们使用的是内置的android.R.layout.simple_list_item_1.xml,
        这里为了将图片和水果名称字符串都放在ListView中的一项中,我们使用自定义布局文件
     -->
        <ImageView
            android:id="@+id/fruit_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
        <TextView
            android:id="@+id/fruit_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10dp" />
    
    </LinearLayout>
    

    接下来就是最重要的,我们要创建自定义的适配器,当前,它要继承ArrayAdapter。新建类FruitAdapter:

    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 java.util.List;
    
    public class FruitAdapter extends ArrayAdapter<Fruit> {
        private int resourceId;
    
        public FruitAdapter(Context context,  int textViewResourceId,  List<Fruit> objects) {
            // 可见,我们的自定义适配器FruitAdapter,在真正的适配部分其实还是调用的ArrayAdapter父类的构造方法
            super(context, textViewResourceId, objects);
            resourceId = textViewResourceId;
        }
    
        @Override
        // 重写ArrayAdapter的getView()方法,这个方法在每个子项滚动到屏幕内时会自动调用
        public View getView(int position,  View convertView,  ViewGroup parent) {
            Fruit fruit = getItem(position);	// 获取当前项的Fruit实例
            // 为每个子项加载我们传入的布局
            View view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
            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;
        }
    }
    

    最后一步,就是更改MainActivity中的代码了:

    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    import android.widget.Toast;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
    
        private List<Fruit> fruitList = new ArrayList<Fruit>();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initFruits();   // 初始化水果数据,初始化fruitList[ ]
            FruitAdapter adapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, fruitList);
            ListView listView = (ListView) findViewById(R.id.list_view);
    
            listView.setAdapter(adapter);   // 设定适配器
            // 为ListView中的每一项都添加一个点击事件监听器
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Fruit fruit = fruitList.get(position);    // 得到点击位置处显示的对应fruitList中的元素
                    Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show();
                }
            });
        }
    
        private void initFruits() {
            // fruitList列表中的每一项内容都是Fruit类型
            for (int i = 0; i < 2; i++) {   // 添加两遍(凑数)
                Fruit apple = new Fruit("Apple", R.drawable.apple_pic);
                fruitList.add(apple);
                Fruit banana = new Fruit("Banana", R.drawable.banana_pic);
                fruitList.add(banana);
                Fruit orange = new Fruit("Orange", R.drawable.orange_pic);
                fruitList.add(orange);
                Fruit watermelon = new Fruit("Watermelon", R.drawable.watermelon_pic);
                fruitList.add(watermelon);
                Fruit pear = new Fruit("Pear", R.drawable.pear_pic);
                fruitList.add(pear);
                Fruit grape = new Fruit("Grape", R.drawable.grape_pic);
                fruitList.add(grape);
                Fruit pineapple = new Fruit("Pineapple", R.drawable.pineapple_pic);
                fruitList.add(pineapple);
                Fruit strawberry = new Fruit("Strawberry", R.drawable.strawberry_pic);
                fruitList.add(strawberry);
                Fruit cherry = new Fruit("Cherry", R.drawable.cherry_pic);
                fruitList.add(cherry);
                Fruit mango = new Fruit("Mango", R.drawable.mango_pic);
                fruitList.add(mango);
            }
        }
    }
    

    image.png
    image

    RecyclerView

      ListView的功能是非常强大的,但也并不是没有缺点,如果我们不使用一些技巧来提示它的运行效率,那么它的性能会非常差。还有,ListView的扩展性也不够好,它只能实现纵向滚动的效果,如果想实现横向滚动的话,ListView就无能为力了。

      为此,Android提供了一个更强大的滚动控件——RecycleView

    布局

    线性布局LinearLayout

    线性布局内控件按水平或垂直方向顺次排布。

    <!-- android命名空间只需要在最顶层的布局中声明一次 -->
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
            <Button
                android:id="@+id/btn1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="I am btn1."
                android:textAllCaps="false"
                android:textColor="#ff0000" />
    
            <Button
                android:id="@+id/btn2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="I am btn2."
                android:textAllCaps="false"
                android:textColor="#ff0000" />
    
            <Button
                android:id="@+id/btn3"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="I am btn3."
                android:textAllCaps="false"
                android:textColor="#ff0000" />
    
            <Button
                android:id="@+id/btn4"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="I am button4."
                android:textAllCaps="false"
                android:textColor="#ff0000" />
    
            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="horizontal"
                android:gravity="center">
                <!-- 嵌套布局 -->
    
                    <Button
                        android:id="@+id/btn5"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="I am btn5"
                        android:textAllCaps="false"
                        android:textColor="#0000ff" />
    
                    <Button
                        android:id="@+id/btn6"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="I am btn6"
                        android:textAllCaps="false"
                        android:textColor="#0000ff" />
    
                    <Button
                        android:id="@+id/btn7"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="I am btn7"
                        android:textAllCaps="false"
                        android:textColor="#0000ff" />
    
                    <Button
                        android:id="@+id/btn8"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="I am btn8"
                        android:textAllCaps="false"
                        android:textColor="#0000ff" />
    
            </LinearLayout>
    
    </LinearLayout>
    

    image.png

    相对布局RelativeLayout

    相对布局可以通过相对定位的方式让控件出现在布局的任意位置上。

    <?xml version="1.0" encoding="utf-8" ?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <Button
            android:id="@+id/btn1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:text="button 1" />
    
        <Button
            android:id="@+id/btn2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:text="button 2" />
    
        <Button
            android:id="@+id/btn3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="button 3" />
    
        <Button
            android:id="@+id/btn4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:text="button 4" />
        <!-- 其内控件可相对于其他控件或父容器排列 -->
    </RelativeLayout>
    

    image.png

    帧布局FrameLayout

    帧布局内所有控件默认都会摆放在布局的左上角。

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="This is TextView" />
    
        <ImageView
            android:id="@+id/img"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/ic_launcher" />
    
    </FrameLayout>
    

    image.png

    百分比布局PercentFrameLayout和PercentRelativeLayout

      前面提到的LinearLayout,RelativeLayout和FrameLayout都是从Android 1.0版本就开始支持了,一直沿用到现在,可以说是满足了绝大多数场景的界面设计需求。不过细心的你还是可以发现,除了LinearLayout支持使用layout_weight属性来实现按比例指定控件大小的功能外,其余两种布局都不支持。比如说如果要使用RelativeLayout来实现让两个按钮平分布局宽度的效果是很困难的。

      为此,Android引入了一种全新的布局方式来解决该问题——百分比问题。在这种布局中,我们可以不再使用wrap_content,match_parent等方式来指定控件的大小,而是允许直接指定控件在布局中所占的百分比,这样一来,就可以轻松实现平分布局甚至是任意比例分割布局的效果。

      由于LinearLayout本身已经支持按比例指定控件大小了,因此百分比布局只为FrameLayout和RelativeLayout进行了功能扩展,提供了PercentFrameLayout和PercentRelativeLayout这两个全新的布局。

      android团队将百分比布局定义在了support库中,只需在build.gradle中添加百分比布局库的依赖,就能保证百分比布局在所有系统版本上都可以使用。在build.gradle(Module:app)中添加一行:

    dependencies {
    	implementation 'com.android.support:percent:28.0.0'
    }
    

    然后就可以使用百分比布局了,因为百分比布局不是直接内置在SDK中的,所以要写出完整的包名。

    <android.support.percent.PercentFrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <Button
            android:id="@+id/button1"
            android:text="Button 1"
            android:layout_gravity="left|top"
            app:layout_widthPercent="50%"
            app:layout_heightPercent="50%" />
    
        <Button
            android:id="@+id/button2"
            android:text="Button 2"
            android:layout_gravity="right|top"
            app:layout_widthPercent="50%"
            app:layout_heightPercent="50%" />
    
        <Button
            android:id="@+id/button31"
            android:text="Button 3"
            android:layout_gravity="left|bottom"
            app:layout_widthPercent="50%"
            app:layout_heightPercent="50%" />
    
        <Button
            android:id="@+id/button4"
            android:text="Button 4"
            android:layout_gravity="right|bottom"
            app:layout_widthPercent="50%"
            app:layout_heightPercent="50%" />
    
    </android.support.percent.PercentFrameLayout>
    

    image.png

    表格布局TableLayout

    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:stretchColumns="1" >
        <!-- 如果某一行控件的总宽不能铺满父容器,则拉伸第一列以适应屏幕宽度 -->
    
        <TableRow>
            <!-- TableRow内无法为控件指定宽度 -->
            <TextView
                android:layout_height="wrap_content"
                android:text="Account:" />
            <EditText
                android:id="@+id/account"
                android:layout_height="wrap_content"
                android:hint="Input your account" />
    
        </TableRow>
    
        <TableRow>
            <TextView
                android:layout_height="wrap_content"
                android:text="Password:" />
            <EditText
                android:id="@+id/password"
                android:layout_height="wrap_content"
                android:inputType="numberPassword" />
        </TableRow>
    
        <TableRow>
            <CheckBox
                android:id="@+id/remember_pass"
                android:layout_height="wrap_content" />
            <TextView
                android:layout_height="wrap_content"
                android:text="remember_password" />
        </TableRow>
    
        <TableRow>
            <Button
                android:id="@+id/login"
                android:layout_height="wrap_content"
                android:layout_span="2"
                android:text="login" />
        </TableRow>
    
    </TableLayout>
    

    image

    创建自定义控件

      所有控件都是直接或间接继承View的,所用的所有部件都直接或间接继承ViewGroup。View是Android中最基本的一种UI组件,它可以在屏幕上绘制一块矩形区域,并能响应这块区域的各种事件。

      因此,我们平常所用的各种组件实际上就是在View的基础上有添加了各自特有的功能。而ViewGroup可以看做是一种特殊的View,它可以包含很多子View和子ViewGroup,是一个用于放置控件和布局的容器。

    image.png

    引入布局

    当系统自带的控件不能满足我们的需求时,可以根据上面的继承关系来实现我们的自定义控件。

    下面我们来自定义一个标题栏。

    首先新建一个布局title.xml,这是用于actionBar的布局文件。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/title_bg">
    
        <Button
            android:id="@+id/title_back"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_margin="5dp"
            android:background="@drawable/back_bg"
            android:text="Back"
            android:textColor="#fff" />
    
        <TextView
            android:id="@+id/title_text"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:gravity="center"
            android:text="Title Text"
            android:textColor="#fff"
            android:textSize="24sp" />
    
        <Button
            android:id="@+id/title_edit"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_margin="5dp"
            android:background="@drawable/edit_bg"
            android:text="Edit"
            android:textColor="#fff" />
    
    </LinearLayout>
    

    然后将这个布局引入到主布局文件activity_main.xml中(使用include标签):

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <include layout="@layout/title" />
    
    </LinearLayout>
    

    可以在app中的每一个布局中引入title.xml,这样每个页面就都拥有我们自定义的标题栏了。

    另外,由于android系统自带有标题栏,所以要将自带的标题栏隐藏掉:

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ActionBar titleBar = getSupportActionBar();
            if(titleBar != null)
                titleBar.hide();
        }
    }
    

    image.png

    back_bg.png edit_bg.png title_bg.png

    自定义控件

      上面的例子中,我们通过引入布局文件,创建了自定义的标题栏。但还是有一个问题,我们要在每个活动中为这些控件单独编写一次事件注册的代码。比如说标题栏返回按钮的Back功能,但事实上,这些功能在每个活动都是一样的实现逻辑。为了避免在每个活动中都注册一遍按钮的点击事件,我们最好使用自定义控件。

    新建java类TitleLayout,继承自LinearLayout类:

    image.png

    public class TitleLayout extends LinearLayout {
    
        public TitleLayout(Context context, AttributeSet attrs) {
            // 将xml中设置的一堆属性全部传给父类LinearLayout的构造函数
            super(context, attrs);
            // 使用from()加载布局title.xml,父布局是TitleLayout本身
            LayoutInflater.from(context).inflate(R.layout.title, this);
    
            Button titleBack = (Button) findViewById(R.id.title_back);
            Button titleEdit = (Button) findViewById(R.id.title_edit);
    
            // 为titleBack控件即返回按钮添加事件监听
            titleBack.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    ((Activity) getContext()).finish();     // 销毁当前上下文活动,退出应用
                }
            });
    
            titleEdit.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(getContext(), "You clicked Edit button", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
    

      然后在主布局activity_main.xml中使用TitleLayout布局,由于TitleLayout是我们自定义的,没有内置在SDK中,所以我们在xml中引入布局时要填写完整的包名。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.example.uiwidgetdemo.TitleLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
        </com.example.uiwidgetdemo.TitleLayout>
    
    </LinearLayout>
    

    image

  • 相关阅读:
    C#深入浅出 修饰符(二)
    HDU 5785 Interesting
    HDU 5783 Divide the Sequence
    HDU 5781 ATM Mechine
    UVA 714 Copying Books
    uva 1471 Defense Lines
    UVA 11134 Fabled Rooks
    UVA 11572 Unique Snowflakes
    UVA 11093 Just Finish it up
    UVA 10954 Add All
  • 原文地址:https://www.cnblogs.com/seeyoumiter/p/12488714.html
Copyright © 2011-2022 走看看