客户端笔记——UI

一.基本布局
二.常用控件
三.RecyclerView
四.自定义视图

〇.绪论

在这里插入图片描述在这里插入图片描述

在这里插入图片描述 View:最最基础的UI组件,一块屏幕上的矩形区域,可响应该区域的各种事件。所有其他控件均继承于View,添加了各自特有的功能。
ViewGroup:特殊的View,用于放控件和布局的容器,可以包含多个 子View 和 子ViewGroup。

tips:

  1. 所有的view都可以设置点击事件
  2. 除了在xml中设置view的属性,还可以在java代码中设置属性。如textView.setText("xxx")
  3. xml中的字符串,通常要在 strings.xml 中声明,通过@String/xxx调用

 

一.Layout 基本布局

Android中有四大基本布局:
LinearLayoutRelativeLayoutFrameLayoutConstraintLayout

 

1.LinearLayout 线性布局

线性排列控件的布局;
LinearLayout 用于使所有子View在单个方向(垂直或水平)保持对齐。

优点:layout_weight属性在屏幕适配时很好用。
缺点:界面较复杂时,需嵌套多层LinearLayout,会降低UI Render效率,还可能引发stackoverflow。

重要属性:

android:orientation:指定布局方向(horizontal or vertiacal)
android:layout_weight:LinearLayout独有,按权重分配屏幕。
例:屏幕只有AB两控件,分别置A控件和B控件的layout_weight为3和2,则A和B按照3:2平分屏幕
指定LinearLayout中layout_weight属性效果
在这里插入图片描述在这里插入图片描述

 

2.RelativeLayout 相对布局

让控件按照相对位置放置的布局(如:以父容器、兄弟控件为参考+margin+padding就可以设置控件位置)
所有子控件默认在左上角堆叠,最后写入的控件位于最上方显示。

优点:原先需多层LinearLayout才能完成的布局,使用相对布局可能仅需一层就可完成。

参考文档:超全解析:RelativeLayout(相对布局)

两种相对方式:

  1. 相对父布局定位(可指定多个属性)
android:layout_alignParentTop="true"   在父布局的上面
android:layout_alignParentBottom="true"   在父布局的下面
android:layout_alignParentLeft="true"   在父布局的左边
android:layout_alignParentRight="true"   在父布局的右边
android:layout_CenterInParent="true"   父布局中心
  1. 相对控件定位
    被引用的布局必须先定义(例子中的button_2必须在之前定义)
android:layout_above="@id/button_2"   在按钮2的上方
android:layout_below="@id/button_2"   在按钮2的下方
android:layout_toLeftOf="@id/button_2"   在按钮2的左边
android:layout_toRightOf="@id/button_2"   在按钮2的右方
android:layout_alignLeft="@id/button_2"   左边缘与按钮2左边缘对齐
android:layout_alignRight="@id/button_2"   右边缘与按钮2右边缘对齐
android:layout_alignTop="@id/button_2"   上边缘与按钮2上边缘对齐
android:layout_alignBottom="@id/button_2"   下边缘与按钮2下边缘对齐

在这里插入图片描述

相对布局示例展示效果
在这里插入图片描述在这里插入图片描述

 
 

3.FrameLayout 帧布局

较为简单,所有控件都默认放在左上角。
控件的位置完全取决于layout_gravity属性。

在这里插入图片描述在这里插入图片描述
4.ConstraintLayout 约束布局

2016年新增的功能;ConstraintLayout使用可视化的拖拽方式绘制界面,AS自动生成xml代码。
优点:使用约束的方式指定控件的位置和关系(更强大版的RelativeLayout),解决复杂布局过多嵌套的问题。

ConstraintLayout完全解析(郭霖)

 
 

二.widget 常用控件

UI控件,各个控件组合起一个界面。

本节介绍了以下控件: TextViewButtonEditTextImageViewProgressBarDialog

0.控件的通用属性
android : layout_height   该控件在布局中的高度
android : layout_width   该控件在布局中的宽度
android : id    为该控件定义一个id,同一个布局中不可以有相同id
android : background   为控件设置背景色或者背景图片
android : padding   设置控件的内间距,即控件内容与控件边界的距离
android : layout_margin   设置控件的外边距,即该控件与其他控件的距离

在这里插入图片描述

android : gravity   控件内容在控件中的对齐方式(控件内部)
android : layout_gravity   控件在父布局中的对齐方式(控件外部)
android : alpha   设置该控件的透明度
android : onClick   为控件的单击事件绑定监听器

android : visibility  设置该控件是否可见{"visible":默认,"inVisible":不可见但占着位置,"gone":不可见}

描述大小的单位:

  1. dp:dip(device independent pixels设备独立像素),不依赖像素,成比例
  2. px:pixels像素
  3. sp:scaled pixels放大像素,用于描述字体大小

 

1.TextView

文本框,显示文本信息。

TextView的特有属性:

android:text   设置文本内容,一般写在string.xml中,通过@String/xxx调用
android:textColor   设置字体颜色,一般写在colors.xml中
android:textStyle   设置字体风格 {"normal":无效果,"bold":加粗,"italic":斜体}
android:textSize   设置字体大小,单位sp   

可以给TextView设置复杂样式,如边框。
步骤:在shapeDrawable中写边框样式的xml文件;将xml中TextView的background属性设置为该边框样式。

边框样式的xmlxml中写TextView实现效果
在这里插入图片描述在这里插入图片描述在这里插入图片描述

菜鸟教程 TextView详解
TextView官方API(英)
 

 

2.Button

按钮,继承自TextView

public class Button extends TextView

Button的特有属性:

android:clickable   是否允许点击;代码中可用setClickable(false)设置
android:onClick   设置点击事件;代码中可用setOnClickListener(OnClickListener I)设置

静态设置监听事件的小例子:

xml布局MainActivity.java实现效果
在这里插入图片描述在这里插入图片描述在这里插入图片描述

动态注册监听事件的两种方法:

匿名类方式实现View.OnClickListener接口方式
在这里插入图片描述在这里插入图片描述

更多资料:
Button详解
菜鸟教程|Button & ImageButton
Button官方API

 
 

3.EditText

继承自TextView,可编辑的文本框,用以获取用户的输入数据。

参考资料:
EditText属性详解 强推!
Android EditText的属性和方法介绍使用及值得注意的点
EditText官方API

布局逻辑显示效果
在这里插入图片描述在这里插入图片描述在这里插入图片描述

EditText特有属性:

android:hint   默认提示文本     
android:textColorHint   提示的颜色

android:selectAllOnFocus="true"   获得焦点(点击EditText)后全选组件内所有文本内容
android:inputType   {"phone":拨号键盘,"textPassword":密码格式,“textVisiblePassword”:密码可见格式...}
android:imeOptions   改变输入法中回车按钮的显示内容

....特别多属性....

补充知识:焦点focus
一个窗口中同一时间只能有一个具有焦点的控件;在非触摸屏设备(Android TV)应用的开发中极为重要。

android:focusableInTouchMode="true"  具有触摸获取焦点的能力
android:focusable="true"  具有普通获取焦点的能力(可以理解为物理键盘)
PS:focusableInTouchMode 比 focusable 更牛逼,前者为true,后者一定为true。

非触摸屏(只能电视)一般用键盘上下左右选中,那个框就是焦点;如果某控件android:focusable="true",则无论怎么上下左右按键都点不到该控件。

手机上大部分控件都不具有触摸获取焦点的能力,即android:focusableInTouchMode="false"(比如Button、TextView、LinearLayout,触摸后他们直接响应点击事件;如果置它们的android:focusableInTouchMode="true",则触摸第一次获取焦点,触摸第二次才会响应点击事件)。EditText默认具有触摸获取焦点的能力。

 

4.ImageView

图片控件,可显示任意图像。

用法:
xml中声明ImageView控件

<ImageView
        android:id="@+id/image_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:src="@mipmap/icon_check"/>

Activity中通过findViewById()获取

public class MainActivity extends RxAppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ImageView imageView = (ImageView) findViewById(R.id.image);
        //可以设置点击事件、切换图片等...	
    }
}

ImageView中 src和background属性的区别

  1. background表示背景,src表示内容
  2. src填入图片,按照图片原大小填充,不拉伸;
    background填入图片,根据ImageView给定的宽度拉伸。

ImageView中adjustViewBounds属性 缩放时是否保持长宽比

以下三件套一起出现才可使用
android:adjustViewBounds="true"   缩放时是否保持长宽比	
android:maxHeight="200px"   ImageView的最大高度
android:maxWidth="200px"   ImageView的最大宽度

ImageView中scaleType属性 设置缩放类型

android:scaleType 缩放类型 Java中通过imageView.setScaleType(ImageView.ScaleType.CENTER);设置

scaleType有很多可选值。
"center":显示在ImageView中心,保持原图大小。如果原图过大,超过部分裁剪处理
"matrix":默认值,显示在ImageView的左上角,超过部分裁剪处理。
"fitCenter":缩放后显示在ImageView的中间。
...

菜鸟教程|ImageView (属性的例子较多)
ImageView官方API

 
 

5.ProgressBar

进度条,系统提供 转圆圈(默认) 和 带进度的长方形 两种进度条。

转圆圈进度条(默认)实现:

xml实现效果
在这里插入图片描述在这里插入图片描述

带进度的进度条实现:

xmljava中设置
在这里插入图片描述在这里插入图片描述
实现效果
在这里插入图片描述

由于自定义的ProgressBar有点丑,通常都会实现自定义的ProgressBar…

菜鸟教程|ProgressBar (含自定义ProgressBar)
ProgressBar官方API

 

6.Dialog
  6.1AlertDialog

在当前界面里弹出一个对话框。该对话框置于最顶部,其他控件都无法交互,通常用于提示重要信息(删除信息前弹出AlertDialog)

java代码显示效果
在这里插入图片描述在这里插入图片描述

AlertDialog可以弹出很多种对话框。包括但不限于下图(代码实现)
在这里插入图片描述
参考资料:
菜鸟教程|AlertDialog
几种AlertDialog及其实现
AlertDialog官方API
 

 

三.RecyclerView

0.ListView

Adapter:适配器。(思想参照设计模式中的适配器模式,适配器类似三相转两相的转接器)
ListView中适配器用作 ListView 和 真实数据 的转接器,通过重载不同参数类型的构造函数,可以实现 真实数据-> ListView 的传递。

ListView的适配器,未优化的自定义适配器的代码。
FruitAdapter:
在这里插入图片描述

上述ListView的性能问题:每个子项滚动至屏幕内都会调用getView(),getView()中都执行一遍 加载布局 和 实例化控件。

优化方案:

  • 引入convertView:避免重复加载布局。
    加载过的布局存在convertView中,这样加载过的布局就不用再被加载一遍了。
    在这里插入图片描述
  • 引入viewHolder:避免重复加载布局。
    实例化过的控件对象存在viewHolder中,findViewById只有第一次才会被调用,实例化过的控件对象不用重复实例化了。
    在这里插入图片描述
1.RecyclerView

RecyclerView,顾名思义带有 回收复用 功能的ListView,更强大的滚动控件,Android官方推荐使用。

优点:

  1. 回收复用的功能。封装ViewHolder的回收复用,可直接面向ViewHolder编写Adapter
  2. 插拔式的体验。高度解藕,针对 布局、动画、分割线都抽象出对应的类,用哪个set哪个。
1.1 RecyclerView 要素

ViewHolder:RecyclerView封装了RecyclerView.ViewHolder(实现了ViewHolder的标准化),写Adapter时直接面向ViewHolder,复用逻辑被封装,写起来更简单。
在RecyclerView.ViewHolder 的三个方法 onCreateViewHolder()、onBindViewHolder()、getItemCount()的重写中写复杂逻辑。

LayoutManager:RecyclerList设置布局管理器LayoutManager以控制item的布局方式。LayoutManager是一个抽象类,他有三个实现类:通过 recyclerView.setLayoutManager(new XxxxLayoutManager(this))的方式设置。

  1. LinearLayoutManager:线性布局,支持横向或纵向
  2. GridLayoutManager:网格布局
  3. StaggeredGridLayoutManager 瀑布流布局

ItemAnimator(可选):RecyclerView提供的动画控制类,控制Item增减动画。

ItemDecoration(可选):设置Item的间隔样式

 

1.2 RecyclerView 的点击事件

RecyclerView没有类似 ListView 的 setOnItemClickListener()之类的注册监听器方法,需要我们自己给子项的具体View去注册点击事件。xxxView.setOnClickListener(..

Q:为什么? ListView 的 setOnItemClickListener()之类注册监听器看起来更方便呀?
A:ListView的 setOnItemClickListener() 只实现对子项的点击事件,想实现子项中的某个按钮的点击事件就比较麻烦;RecyclerView的注册方式更为灵活,可实现对子项其中具体某个View的点击事件。

 

1.3 RecyclerView的demo

1. build.gradle 中添加依赖

implementation 'androidx.recyclerview:recyclerview:1.1.0'

2. MeiziAdapter.java

public class MeiziAdapter extends RecyclerView.Adapter<MeiziAdapter.ViewHolder> {
    List<Meizi> mData;
    Context context;
    public MeiziAdapter(Context context, List<Meizi> meiziList){
        this.context = context;
        this.mData = meiziList;
    }
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View itemView = inflater.inflate(R.layout.meizi_item,parent,false); //引入item的布局
        final ViewHolder holder = new ViewHolder(itemView);
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int position = holder.getAdapterPosition();//通过viewHolder获得position
                Meizi meizi = mData.get(position); //获得Adapter中对应position的数据
                Toast toast = Toast.makeText(view.getContext(),"您已点击 妹子"+position,Toast.LENGTH_SHORT);
                toast.show();
                //更新列表项
                meizi.setContent(meizi.getContent()+"已点击");
                notifyItemChanged(position); //通知recyclerView指定position已更改
            }
        });
        return holder;
    }

    //写滚动到指定item时,对控件的行为
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
        Meizi meizi = mData.get(position);
        holder.textView.setText(meizi.getContent());
    }

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

    ViewHolder内部类 实例化控件
    class ViewHolder extends RecyclerView.ViewHolder{
        View itemView;
        ImageView imageView;
        TextView textView;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            this.itemView = itemView;
            imageView = itemView.findViewById(R.id.imageView);
            textView = itemView.findViewById(R.id.comment);
        }
    }
}

3. 数据类 Meizi.java

public class Meizi {
    private String content;
    public Meizi(String content){
        this.content = content;
    }
    public String getContent(){
        return content;
    }
    public void setContent(String content){
        this.content = content;
    }
}

4. 每一项的布局 meizi_item.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="157dp"
        android:layout_height="125dp"
        android:layout_marginStart="8dp"
        android:scaleType="centerCrop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.073"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0"
        app:srcCompat="@drawable/meizi"
        tools:ignore="ContentDescription" />

    <TextView
        android:id="@+id/comment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

5. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

	<!--加了个RecyclerView,具体布局meizi_item.xml在java代码中指定-->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

6.MainActivity.java

public class MainActivity extends AppCompatActivity {
    private List<Meizi> meiziList = new ArrayList<Meizi>();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        MeiziAdapter adapter = new MeiziAdapter(this,meiziList); //数据传入Adapter
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
        RecyclerView recyclerView = findViewById(R.id.recyclerView); //拿到recyclerview
        //给recyclerView设置setxxx()各种
        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(layoutManager);
    }

    private void initData(){
        for(int i=0;i<100;++i){
            meiziList.add(new Meizi("妹子"+i));
        }
    }
}

效果:
滑动后,点击每个item,弹出toast “您已点击妹子几”,同时改变RecyclerView中文字的显示。
在这里插入图片描述

 
 

四.View 自定义视图

知识很多,很重要的部分,还需深入学习。

0.背景知识

在这里插入图片描述

Activity: 控制器,只是控制生命周期和处理事件,控制视图的实际上是Window。一个Activity包含了一个Window,Window才是真正代表一个窗口。Activity就像一个控制器,统筹视图的添加与显示,以及通过其他回调方法,来与Window、以及View进行交互。

Window:(视图的)承载器,Window是一个抽象类,实际在Activity中持有的是其子类PhoneWindow。PhoneWindow内部持有一个 DecorView。

DecorView:顶级view,所有view的最外层布局。DecorView是FrameLayout的子类,它可以被认为是Android视图树的根节点视图。DecorView包含标题栏和内容栏。

ViewRoot:连接器,负责WindowManagerService与DecorView之间的通信。对应ViewRootImpl类,View的三大流程(测量(measure),布局(layout),绘制(draw))均通过ViewRoot来完成。
负责交互,Android的所有触屏事件、按键事件、界面刷新等事件都是通过ViewRoot进行分发的。

在这里插入图片描述
用户点击屏幕产生一个触摸行为,触摸行为 通过硬件捕获 -> ViewRootImpl -> DecorView -> PhoneWindow -> Activity

参考文章:Window、Activity、DecorView、ViewRoot之间的关系

1.Android自定义View

单纯用系统的控件和布局不能满足要求,我们可以自定义View去实现界面。(系统控件也是人写的,别人能写我也能写)

必读:
Android自定义View全解
View测量、布局及绘制原理
选读:
Android自定义View的各种姿势
Android创建自定义的View类
在这里插入图片描述

 
《第一行代码》的demo1:创建一个自定义的标题栏(引入自定义布局)

1.新建一个布局title.xml
左边一个Back,中间Tile,右边Edit

在这里插入图片描述
在这里插入图片描述

2.在activity_main.xml中使用该标题栏
在这里插入图片描述
3.在MainActivity中隐藏系统自带的标题栏
在这里插入图片描述
效果:
在这里插入图片描述

《第一行代码》的demo2:创建自定义的控件(使用自定义控件)

新建自定义标题栏控件TitleLayout继承自LinearLayout

在这里插入图片描述
在这里插入图片描述
修改activity_main.xml中代码,添加自定义控件
在这里插入图片描述
通过这种方式实现各个界面可以复用一个TitleLayout。实现效果如下:
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值