《第一行代码》学习笔记——第三章 UI开发

常用控件

TextView

示例代码:

	<TextView
	    android:id="@+id/text_view"
	    android:layout_width="match_parent"
	    android:layout_height="wrap_content"
	    android:gravity="center"
	    android:textSize="24sp"
	    android:textColor="#00ff00"
	    android:text="This is TextView"/>

android:gravity指定文字对齐方式,可选top,bottom,left,right,center等。可以用“|”来同时指定多个值。
android:textSize指定文字的大小
android:textColor指定文字的颜色

Button

示例代码:

	activity_main.xml
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="Button" />

	MainActivity.java
	button = findViewById(R.id.button);
	button.setOnClickListener(new View.OnClickListener() {
		   @Override
		   public void onClick(View v) {
		       
		   }
		});

android:textAllCaps是否对所有因为字母自动大写

EditText

示例代码:

    <EditText
        android:id="@+id/edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Type something here"
        android:maxLines="2"/

android:hint指定一段提示性文字
android:maxLines指定EditText最大行数

ImageView

示例代码:

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/img_1"/>

ProgressBar

ProgressBar用于在界面上显示一个进度条。
示例代码:

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="visible"/>

可以通过在代码中设置ProgressBar的visibility来显示和隐藏进度。
通过设置style修改ProgressBar的样式,如下为水平进度条:

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="?android:attr/progressBarStyleHorizontal"
        android:max="100"/>

AlertDialog

AlertDialog可以在当前界面弹出一个对话框,这个对话框置顶于所有界面元素之上,能够屏蔽掉其他控件的交互能力。
示例代码:

	AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
	builder.setTitle("This is Dialog")
	        .setMessage("Something important")
	        .setCancelable(false)
	        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
	            @Override
	            public void onClick(DialogInterface dialog, int which) {
	
	            }
	        })
	        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
	            @Override
	            public void onClick(DialogInterface dialog, int which) {
	
	            }
	        });
	builder.show();

ProgressDialog

ProgressDialog会在对话框中显示一个进度条。
示例代码:

	ProgressDialog dialog = new ProgressDialog(MainActivity.this);
	dialog.setTitle("This is ProgressDialog");
	dialog.setMessage("Loading...");
	dialog.setCancelable(true);
	dialog.show();

可以使用ProgressDialog的dismiss()方法关闭对话框。

4种基本布局

线性布局

LinearLayout又称作线性布局,该布局会将它所包含的控件在线性方向上依次排列。通过设置android:orientation属性指定排序方向,vertical或者horizontal。

相对布局

RelativeLayout又称作相对布局,它可以通过相对定位的方式让控件出现在布局的任何位置。
相对父布局进行定位:
android:layout_alignParentLeft:左对齐
android:layout_alignParentRight:右对齐
android:layout_ailgnParentTop:上对齐
android:layout_alignParentBottom:下对齐
android:layout_centerInParent:居中
相对控件进行定位:
android:layout_above:让该控件位于另一个控件上方
android:layout_below:让该控件位于另一个控件下方
android:layout_toLeftOf:让该控件位于另一个控件左侧
android:layout_toRightOf:让该控件位于另一个控件右侧
android:layout_alignLeft:让该控件的左边缘和另一个控件的左边缘对齐
android:layout_alignRight:让该控件的右边缘和另一个控件的右边缘对齐
android:layout_alignTop:让该控件的上边缘和另一个控件的上边缘对齐
android:layout_alignBottom:让该控件的下边缘和另一个控件的下边缘对齐

帧布局

FrameLayout又称作帧布局,该布局没有方便的定位方式,所有控件都会默认摆放在布局的左上角。

百分比布局

百分比布局只为FrameLayout和RelativeLayout进行了功能扩展,提供了PercentFrameLayout和PercentRelativeLayout两个新的布局。
该布局不在系统库中,需要引入:

    implementation 'com.android.support:percent:30.0.1'

创建自定义控件

引入布局

  1. 新建布局title.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="wrap_content"
    android:background="@color/colorPrimary">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        android:background="@color/colorAccent"
        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="@color/colorAccent"
        android:text="Edit"
        android:textColor="#fff"/>

</LinearLayout>
  1. 在activity_main.xml中引入布局:
    <include layout="@layout/title"/>
  1. 在Activity中隐藏自系统自带的标题栏:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.hide();
        }
    }

创建自定义控件

  1. 新建TitleLayout类:
public class TitleLayout extends LinearLayout {

    public TitleLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        LayoutInflater.from(context).inflate(R.layout.title, this);
    }
}
  1. 为标题栏中的Button注册事件:
    public TitleLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        LayoutInflater.from(context).inflate(R.layout.title, this);

        Button titleBack = findViewById(R.id.title_back);
        Button titleEdit = findViewById(R.id.title_edit);

        titleBack.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                ((Activity)getContext()).finish();
            }
        });
        titleEdit.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getContext(), "You clicked Edit button", Toast.LENGTH_SHORT).show();
            }
        });
    }
  1. 在Activity的xml中使用该布局:
    <com.lhh.uicustomviews.TitleLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

ListView

简单用法

  1. 在xml中使用ListView控件:
    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  1. 在Activity中设置ListView:
    private ListView listView;

    private String[] data = {
        "Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape", "Pineapple", "Strawberry",
            "Cherry", "Mango"
    };

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

        ArrayAdapter<String> adapter
                = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, data);
        listView = findViewById(R.id.list_view);
        listView.setAdapter(adapter);
    }

定制ListView界面

  1. 新建Fruit实体类:
public class Fruit {

    private String name;

    private int imageId;

    public Fruit(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }

    public String getName() {
        return name;
    }

    public int getImageId() {
        return imageId;
    }
}
  1. 为ListView新建子项布局fruit_item.xml:
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <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_marginStart="10dp"/>

</LinearLayout>
  1. 新建自定义适配器FruitAdapter:
public class FruitAdapter extends ArrayAdapter<Fruit> {

    private int resourceId;

    public FruitAdapter(@NonNull Context context, int resource, @NonNull List<Fruit> objects) {
        super(context, resource, objects);
        resourceId = resource;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        Fruit fruit = getItem(position);
        View view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
        ImageView fruitImage = view.findViewById(R.id.fruit_image);
        TextView fruitName = view.findViewById(R.id.fruit_name);
        fruitImage.setImageResource(fruit.getImageId());
        fruitName.setText(fruit.getName());
        return view;
    }
}
  1. 在Activity中设置ListView:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FruitAdapter adapter = new FruitAdapter(this, R.layout.fruit_item, fruitList);
        listView = findViewById(R.id.list_view);
        listView.setAdapter(adapter);
    }

提升ListView的运行效率

ListView控件的使用难度在于其有许多细节可以优化,其中运行效率就是很重要的一点。当前在getView()方法中,每次都将布局重新加载了一遍,所以运行效率很低。

  1. 复用View。getView()方法中的converView参数是用于将之前加载好的布局进行缓存,以便之后可以重用:
    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        Fruit fruit = getItem(position);
        View view;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
        } else {
            view = convertView;
        }
        ImageView fruitImage = view.findViewById(R.id.fruit_image);
        TextView fruitName = view.findViewById(R.id.fruit_name);
        fruitImage.setImageResource(fruit.getImageId());
        fruitName.setText(fruit.getName());
        return view;
    }
  1. 缓存控件实例。在getView()方法中每次还是需要调用findViewById()方法来获取控件实例。可以借助ViewHolder来进行优化:
    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        Fruit fruit = getItem(position);
        View view;
        ViewHolder viewHolder;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.fruitImage =  view.findViewById(R.id.fruit_image);
            viewHolder.fruitName = view.findViewById(R.id.fruit_name);
            view.setTag(viewHolder);
        } else {
            view = convertView;
            viewHolder = (ViewHolder)view.getTag();
        }
        viewHolder.fruitImage.setImageResource(fruit.getImageId());
        viewHolder.fruitName.setText(fruit.getName());
        return view;
    }
    
    class ViewHolder {
        ImageView fruitImage;
        TextView fruitName;
    }

ListView的点击事件

示例代码:

	listView.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, fruit.getName(), Toast.LENGTH_SHORT).show();
	    }
	});

RecyclerView

RecyclerView是增强版的ListView。实现了ListView同样的效果,并且优化了ListView的许多不足。
使用RecyclerView需要引入依赖:

    implementation 'androidx.recyclerview:recyclerview:1.1.0'

基本使用

  1. 新建Fruit实体类和fruit_item.xml子项布局,同上
  2. 新建适配器FruitAdapter:
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {

    private List<Fruit> fruitList;

    public FruitAdapter(List<Fruit> fruitList) {
        this.fruitList = fruitList;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Fruit fruit = fruitList.get(position);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
    }

    @Override
    public int getItemCount() {
        return fruitList.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {

        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            fruitImage = itemView.findViewById(R.id.fruit_image);
            fruitName = itemView.findViewById(R.id.fruit_name);
        }
    }
}
  1. 在Activity中设置RecyclerView:
    private List<Fruit> fruitList = new ArrayList<>();
    private RecyclerView recyclerView;

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

        recyclerView = findViewById(R.id.recycler_view);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        FruitAdapter fruitAdapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(fruitAdapter);
    }

实现横向滚动

  1. 修改fruit_item.xml以适配横向滚动:
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>

    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"/>

</LinearLayout>
  1. 在Activity中设置RecyclerView为横向滚动
	LinearLayoutManager layoutManager = new LinearLayoutManager(this);
	layoutManager.setOrientation(RecyclerView.HORIZONTAL);
	recyclerView.setLayoutManager(layoutManager);

实现瀑布流

  1. 修改fruit_item.xml:
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp">

    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>

    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_marginTop="10dp"/>

</LinearLayout>
  1. 在Activity中配置RecyclerView的LayoutManager:
	StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
	
	recyclerView.setLayoutManager(layoutManager);

RecyclerView的点击事件

RecyclerView没有提供类似setOnItemClickListener()的注册监听的方法。需要自己给子项具体的View注册点击事件。虽然比ListView要复杂一点,但因此也可以为子项的所有元素各自添加事件。

  1. 修改FruitAdapter.ViewHolder:
    static class ViewHolder extends RecyclerView.ViewHolder {

        View fruitView;
        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            fruitView = itemView;
            fruitImage = itemView.findViewById(R.id.fruit_image);
            fruitName = itemView.findViewById(R.id.fruit_name);
        }
    }
  1. 修改FruitAdapter的onCreateViewHolder()方法:
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);
        final ViewHolder viewHolder = new ViewHolder(view);
        viewHolder.fruitView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = viewHolder.getAdapterPosition();
                Fruit fruit = fruitList.get(position);
                Toast.makeText(v.getContext(), "You clicked view " + fruit.getName(), Toast.LENGTH_SHORT).show();
            }
        });
        viewHolder.fruitImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = viewHolder.getAdapterPosition();
                Fruit fruit = fruitList.get(position);
                Toast.makeText(v.getContext(), "You clicked image " + fruit.getName(), Toast.LENGTH_SHORT).show();
            }
        });
        return viewHolder;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值