网络知识 娱乐 Android入门基础教程

Android入门基础教程

第1章 Android Studio运行第一个程序

1.1 Android Studio下载:

1.1.1 Android开发者官网:

        https://developer.android.google.cn

1.1.2 下载Android Studio开发者工具:

  1. 进入Android开发者官网;
  2. 找到Android Studio工具下载页面;
  3. 点击“Download option”按钮选择与自己系统对应的版本(本人使用的是Windows版本);
  4. 同意“条款和条件”并点击下载;

1.2 Android Studio安装:

  1. 双击下载好的Android Studio工具;
  2. 直接点击“Next”到安装处点击“Install”安装;(中途有:欢迎安装界面-->选择上虚拟设备-->安装路径)
  3. 等待安装完成后点“Next”如下图所示表示安装完成;                                                               
  4. 运行Android Studio;(由于是第一次安装,没有配置文件,直接点击“OK”)
  5. 点击“Cancel”;                                                                                                                                                  
  6. 会弹出欢迎界面,提示会提醒是否将使用情况统计信息发送到“Google”;(单纯让谷歌知道多了一位Android开发者)
  7. 来到欢迎配置Android Studio开发环境,点击”Next“直接到License Agreement[许可协议];(【Install Type:安装类型】[Standard:标准]-->【Select Ul Theme:选择UI主题】-->【Verify Settings:验证配置】)
  8. 阅读并同意安装组件的许可协议,点击“Finish”;([License Agreement:许可协议]、[Accept:接受])
  9. 下载完成后,点击“Finish”;

1.3 Android Studio卸载:

  1. 卸载Android Studio软件;(默认安装路径:C:Program FilesAndroidAndroid Studio)
  2. 删除SDK文件夹;(默认路径:C:用户Administrator[用户名]AppDataLocalAndroidsdk)
  3. 删除相关文件夹;(默认路径:C:用户Administrator[用户名])
    删除.android 文件夹
    删除 .AndroidStudioX.X 文件夹
    删除.gradle 文件夹

具体详见:https://blog.csdn.net/weixin_45048331/article/details/111868109

1.4 第一个Android应用程序:

1.4.1 创建Android工程项目:

  1. 将Android Studio工具的快捷启动放到桌面;
  2. 点击“New Project”;
  3. 选择Phone and Table-->选择“Empty Activity”-->点击“Next”;
  4. 【Name:app的名字】-->【Package name:包名】-->【Save location:保存路径】-->【Language:语言】-->【点击“Finish”】;
  5. 然后等待下载完成Gradle配置工具;(某些用户可能会弹出防火墙的“安全中心警告”,点击“允许访问”)
  6. 打开“activity_main.xml”文件,视图效果和模拟器上运行的效果差不多

1.4.2 运行第一个Android应用程序:

  • 添加手机模拟器
  1. 点击下图右边第4个像手机一样的图标;
  2. 点击“Create virtual device”添加手机模拟器;
  3. 选上自己喜欢的设备,然后点击“Next”;(可点击“New Hardware Profile”自定义模拟设备)
  4. 点击“Download”下载模拟设备的系统镜像;
  5. 选择已下载的模拟设备系统镜像,点击“Next”;
  6. 给模拟设备命名,点击“”Finish;
  7. 点击“播放按钮”给模拟设备开机;                                                                                      
  8. 手机仿真器视图显示设置;                                                                                                             
  9. 点击运行按钮后的运行结果;                                                                                                     
  10. 编码方式与视图设计方式切换在编辑框的右上角,仿真器隐藏后在编辑框的右边栏最下方(【Code、Split、Design】、【Emulator:仿真器】);

1.4.3 仿真程序进程终止问题

  • 问题描述:Android Studio运行自带模拟器报The emulator process for AVD Pixel_4a_Edited_API_28 has terminated.
  • 原因分析:虚拟机安装路径存在中文符号导致乱码。因为Android Studio会默认安装虚拟机在用户目录下,如果你的电脑用户名带中文,比如C:Users 张三,因为当前用户路径有中文符号,导致一些配置文件中的路径会乱码,这时虚拟机就会运行失败。
  • 解决方法:解决Android Studio运行模拟器报:The emulator process for AVD Pixel_4a_Edited_API_28 has terminated._晨曦的博客-CSDN博客

1.5 Android工程结构介绍

修改工程结构显示方式,将Android修改成Project[以目录结构显示];为不影响显示效果此部分内容请使用PC端查看

├── .gradle                                                                                # AS自动生成的文件,AS会自动修改它的,项目打包时也会删除;
├── .idea                                                                                   # AS自动生成的文件,AS会自动修改它的,项目打包时也会删除;
├── app                                                                                     # 应用相关的东西都在里面,工作的核心目录 
│        ├── build                                                                         # 编译的产物。某些情况下,可以手动把它整个删掉。
│        ├── libs                                                                           # 依赖包可以放这里,比如一些jar文件。
│        ├── src                                                                            # 代码在这。非常重要。
│        │        ├── main
│        │        │        ├── java                                                      # 放Java代码的地方
│        │        │        ├── res 
│        │        │        │        ├── drawable                                    # 应用图标
│        │        │        │        ├── layout                                         # Android布局文件夹
│        │        │        │        ├── mipmap                                      # 桌面图标
│        │        │        │        ├── layout                                         # Android布局文件夹
│        │        │        │        └── values                                        # 颜色、样式、字符集配置文件夹
│        ├── .gitignore                                                                   # 版本控制
│        ├── build.gradle                                                               # 非常重要,app的构建配置。俗称“app的gradle文件”。
│        └── proguard-rules.pro                                                    # 先不管。这个是混淆配置。
├── gradle                                                                                  # 它是一个构建起配置文件
├── .gitignore                                                                             # 整个工程的版本控制
├── build.gradle                                                                         # 很重要。项目级的配置。俗称“项目gradle文件”。
├── gradle.properties                                                                 # 全局的gradle配置文件
├── gradlew                                                                                # Linux/mac上执行gradle命令
├── gradlew.bat                                                                          # Windows上执行gradle命令
├── local.properties                                                                    # 本地配置文件,一般不上传
└── settings.gradle                                                                     # gralde的项目级配置

第2章 Android的UI控件

注:控件的属性值可以【Ctrl+鼠标左键】进行查看

2.1 TextView(文本框)

本节前言:

dp(dip): device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。 

px: pixels(像素). 不同设备显示效果相同,一般我们HVGA代表320x480像素,这个用的比较多。 

pt: point,是一个标准的长度单位,1pt=1/72英寸,用于印刷业,非常简单易用; 

sp: scaled pixels(放大像素). 主要用于字体显示best for textsize。

2.1.1 基础属性详解: 

  • id:为TextView设置一个组件id,根据id,我们可以在Java代码中通过findViewById(R.id.tv_one)的方法获取到该对象,然后进行相关属性的设置,又或者使用RelativeLayout时,参考组件用的也是id!
  • layout_width:组件的宽度,一般写:**wrap_content**或者**match_parent(fill_parent)**,前者是控件显示的内容多大,控件就多大,而后者会填满该控件所在的父容器;当然也可以设置成特定的大小,比如我这里为了显示效果,设置成了200dp。
  • layout_height:组件的高度,内容同上。
  • gravity:设置控件中内容的对齐方向,TextView中是文字,ImageView中是图片等等。
  • text:设置显示的文本内容,一般我们是把字符串写到src/main/res/values/string.xml文件中,然后通过@String/xxx取得对应的字符串内容的,这里为了方便我直接就写到""里,不建议这样写!!!
  • textColor:设置字体颜色,同上,通过src/main/res/values/colors.xml资源来引用,然后通过@String/xxx进行引用,别直接这样写!
  • textStyle:设置字体风格,三个可选值:**normal**(无效果),**bold**(加粗),**italic**(斜体)
  • textSize:字体大小,单位一般是用sp!
  • background:控件的背景颜色,可以理解为填充整个控件的颜色,可以是图片哦!

XML代码:

    

2.1.2 带阴影的TextView

  • android:shadowColor:设置阴影颜色,需要与shadowRadius一起使用哦!
  • android:shadowRadius:设置阴影的模糊程度,设为0.1就变成字体颜色了,建议使用3.0
  • android:shadowDx:设置阴影在水平方向的偏移,就是水平方向阴影开始的横坐标位置
  • android:shadowDy:设置阴影在竖直方向的偏移,就是竖直方向阴影开始的纵坐标位置

 XML代码:

    

2.1.3 实际开发例子——跑马灯效果

  • android:singleLine:内容单行显示
  • android:focusable:是否可以获取焦点
  • android:focusablelnTouchMode:用于控制视图在触摸模式下是否可以聚焦
  • android:ellipsize:在哪里省略文本
  • android:marqueeRepeatLimit:字幕动画重复的次数

更多详见:2.3.1 TextView(文本框)详解 | 菜鸟教程 (runoob.com)

XML代码: 

    

默认情况下没有效果:

  1. 开启可点击:android:clickable="true"
  2. 添加一个请求标签:
  3. 写一个类继承TextView实现其方法,并重写isFocused()方法返回true,然后将TextView标签给出自定义的全类名

2.2 Button(按钮)

本节前言:

Button是TextView的子类,所以TextView上很多属性也可以应用到Button 上!我们实际开发中对于Button的,无非是对按钮的几个状态做相应的操作,比如:按钮按下的时候 用一种颜色,弹起又一种颜色,或者按钮不可用的时候一种颜色这样!上述实现无非是通过 StateListDrawable这种Drawable资源来实现,即编写一个drawable的资源文件。

2.2.1 StateListDrawable介绍:

StateListDrawable是Drawable资源的一种,可以根据不同的状态,设置不同的图片效果,关键节点 ,我们只需要将Button的background属性设置为该drawable资源即可轻松实现,按下 按钮时不同的按钮颜色或背景!

  • drawable:引用的Drawable位图,我们可以把他放到最前面,就表示组件的正常状态~
  • state_focused:是否获得焦点
  • state_window_focused:是否获得窗口焦点
  • state_enabled:控件是否可用
  • state_checkable:控件可否被勾选,eg:checkbox
  • state_checked:控件是否被勾选
  • state_selected:控件是否被选择,针对有滚轮的情况
  • state_pressed:控件是否被按下
  • state_active:控件是否处于活动状态,eg:slidingTab
  • state_single:控件包含多个子控件时,确定是否只显示一个子控件
  • state_first:控件包含多个子控件时,确定第一个子控件是否处于显示状态
  • state_middle:控件包含多个子控件时,确定中间一个子控件是否处于显示状态
  • state_last:控件包含多个子控件时,确定最后一个子控件是否处于显示状态

更多详见:3.3.3 Button(按钮)与ImageButton(图像按钮) | 菜鸟教程 (runoob.com)

  1.    在src/main/res/drawable中添加位矢图和new按钮选择器【btn_selecter.xml】
  2. 默认情况下新版本的AS设置背景颜色是无效果的,需要修改themes.xml文件
  3. 在src/main/res中new按钮的颜色选择器【color/btn_color_selecter.xml】

XML代码: 

    

 运行效果图: 

 

2.2.2 常见的Button事件:

  • 单击事件:setOnClickListener()
  • 长按事件:setOnLongClickListener()
  • 触摸/移动事件:setOnTouchListener()

代码中TAG的值为“leo”

运行结果1(长按+移动):setOnLongClickListener()与setOnTouchListener()的返回值为false

 运行结果2(长按+移动):setOnLongClickListener()返回值为false,setOnTouchListener()的返回值为true,会将setOnLongClickListener()取代(即触摸/移动也会触发)

 运行结果3(长按+移动):setOnLongClickListener()返回值为true,setOnTouchListener()的返回值为false,setOnClickListener()不会执行

onClickListener()的另一种写法:在activity_main.xml的Button标签中写android:onClick="leoClick",再按住Alt+Enter创建leoClick方法,优先级低于setOnClickListener()

2.3 EditText(输入框)

2.3.1 主要属性

  • android:hint输入提示
  • android:textColorHint输入提示文字的颜色
  • android:inputType输入类型
  • android:drawableXxoxx在输入框的指定方位添加图片
  • android:drawablePadding设置图片与输入内容的间距
  • android:paddingXxxx设置内容与边框的间距
  • android:background背景色

更多详见:2.3.2 EditText(输入框)详解 | 菜鸟教程 (runoob.com)

 XML代码:

    

    

    

    

 运行效果图:

2.3.2 实际开发例子——用户登录

运行效果图:edit_background.xml是文本框

2.4 ImageView(图像视图)

2.4.1 主要属性

  • android:src设置图片资源
  • android:scaleType设置图片缩放类型
  • android:maxHeight最大高度
  • android:maxWidth最大宽度
  • android:adjustViewBounds是否调整View的界限

 XML代码:

    

    

运行效果图:

2.4.2 scaleType的属性

  • fitStart:保持宽高比缩放图片,直到较长的边与lmage的边长相等缩放完成后将图片放在ImageView的左上角
  • fitCenter:默认值,同上,缩放后放于中间
  • fitEnd:同上,缩放后放于右下角
  • fitXY:对图像的横纵方向进行独立缩放,使得该图片完全适应lmageView,但是图片的宽高比可能会发生改变
  • center:保持原图的大小,显示在ImageView的中心。 当原图的size大于ImageView的size,超过部分裁剪处理。
  • centerCrop:保持宽高比缩放图片,直到完全覆盖ImageView,可能会出现图片的显示不完全
  • centerInside:保持宽高比缩放图片,直到ImageView能够完全地显示图片
  • matrix:不改变原图的大小,从ImageView的左上角开始绘制原图,原图超过ImageView的部分作裁剪处理

更多详见:2.3.4 ImageView(图像视图) | 菜鸟教程 (runoob.com)

2.5 ProgressBar(进度条)

 2.5.1 常用属性详解

  • android:max:进度条的最大值
  • android:progress:进度条已完成进度值
  • android:indeterminate:如果设置成true,则进度条不精确显示进度
  • style="?android:attr/progressBarStyleHorizontal"水平进度条

更多详见:ProgressBar(进度条) | 菜鸟教程 (runoob.com)

 XML代码:

    
    

 Java代码:

public class MainActivity extends AppCompatActivity {
    private ProgressBar pb1;
    private ProgressBar pb2;
    private Integer speed;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pb1 = findViewById(R.id.pb1);
        pb2 = findViewById(R.id.pb2);
        speed = (int)(pb2.getMax() * 0.1);
    }

    public void leoClick(View view) {
        if (pb1.getVisibility() == View.GONE) {
            pb1.setVisibility(View.VISIBLE); //显示
        } else {
            pb1.setVisibility(View.GONE);
        }
    }

    public void loadClick(View view) {
        int progress = pb2.getProgress();
        pb2.setProgress(progress + speed);
    }
}

运行效果图:

2.6 Notification(状态栏通知)

2.6.1 Notification的基本使用流程

状态通知栏主要涉及到2个类:Notification 和NotificationManager

Notification:通知信息类,它里面对应了通知栏的各个属性

NotificationManager:是状态栏通知的管理类,负责发通知、清除通知等操作。

使用的基本流程:

  • Step 1. 获得NotificationManager对象: NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
  • Step 2. 创建一个通知栏的Builder构造类: Notification.Builder nBuilder = new Notification.Builder(this);
    在老的版本中是使用Notification()
    新的版本是使用Notification.Builder()
    为了兼容性现在使用NotificationCompat.Builder()
  • Step 3. 对Builder进行相关的设置,比如标题,内容,图标,动作等!
  • Step 4. 调用Builder的build()方法为notification赋值
  • Step 5. 调用NotificationManager的notify()方法发送通知!
  • PS:另外我们还可以调用NotificationManager的cancel()方法取消通知

2.6.2 NotificationChannel(通知渠道)

通知渠道,Android 8.0引入了通知渠道,其允许您为要显示的每种通知类型创建用户可自定义的渠道。
通知重要程度设置,NotificationManager类中

  • IMPORTANCE_NONE:关闭通知
  • IMPORTANCE_MIN:开启通知,不会弹出,但没有提示音,状态栏中无显示
  • IMPORTANCE_LOW:开启通知,不会弹出,不发出提示音,状态栏中显示
  • IMPORTANCE_DEFAULT(默认):开启通知,不会弹出,发出提示音,状态栏中显示
  • IMPORTANCE_HIGH:开启通知,会弹出,发出提示音,状态栏中显示

2.6.3 Notification的常见方法

  • setContentTitle(String string):设置标题
  • setContentText(String string):设置文本内容
  • setSmalllcon(int icon):设置小图标
  • setLargelcon(Bitmap icon):设置通知的大图标
  • setColor(int argb):设置小图标的颜色
  • setContentlntent(Pendinglntent intent):设置点击通知后的跳转意图
  • setAutoCancel(boolean boolean):设置点击通知后自动清除通知
  • setWhen(long when):设置通知被创建的时间

注意:Android从5.0系统开始,对于通知栏图标的设计进行了修改。现在Google要求,所有应用程序的通知栏图标,应该只使用alpha图层来进行绘制,而不应该包括RGB图层。

2.6.3 实际例子——模拟通知

 XML代码:

Java代码:

运行效果:

更多详见:2.5.8 Notification(状态栏通知)详解 | 菜鸟教程 (runoob.com)

2.7 Toolbar(工具栏目)

2.7.1 常用属性详解

取消系统默认的标题栏目:src/main/res/values/themes.xml --> style标签 --> parent="Theme.MaterialComponents.DayNight.NoActionBar"

  • android:layout_width="match_parent"
  • android:layout_height=""?attr/actionBarSize":使用的是ActionBar的高度
  • android:background="#FFFF00"
  • app:navigationlcon=" @drawable/ic_baseline_arrow_back_24""
  • app:title="主标题"
  • app:titleTextColor="#FF0000"
  • app:titleMarginStart="90dp":左间距
  • app:subtitle="子标题"
  • app:subtitleTextColor="#00FFFFF"
  • app:logo="@mipmap/ic_launcher"

 使用ToolBar替换系统默认的DarkActionBar:

XML代码:




    

Java代码: 

public class MainActivity extends AppCompatActivity {

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

        Toolbar toolbar = findViewById(R.id.tb); //androidx.appcompat.widget.Toolbar
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.e("leo","ToolBar被点击了!");
            }
        });
    }
}

运行效果图: 

2.7.2 标题居中显示

代码及运行效果:

2.8 AlertDialog(对话框)

2.8.1 实现方式/使用流程

  • AlertDialog.Builder builder = new AlertDialog.Builder(context); 构建Dialog的各种参数
  • Builder.setlcon(int iconld); 添加ICON
  • Builder.setTitle(CharSequence title); 添加标题
  • Builder.setMessage(CharSequence message);添加消息
  • Builder.setView(View view); 设置自定义布局
  • setPositiveButton:确定按钮
  • setNegativeButton:取消按钮
  • setNeutralButton:中间按钮
  • Builder.create(); 创建Dialog
  • Builder.show(); 显示对话框

使用流程:

  • Step 1:创建AlertDialog.Builder对象;
  • Step 2:调用setIcon()设置图标,setTitle()setCustomTitle()设置标题;
  • Step 3:设置对话框的内容:setMessage()还有其他方法来指定显示的内容;
  • Step 4:调用setPositive/Negative/NeutralButton()设置:确定,取消,中立按钮;
  • Step 5:调用create()方法创建这个对象,再调用show()方法将对话框显示出来;

更多详见:2.5.9 AlertDialog(对话框)详解 | 菜鸟教程 (runoob.com)

XML代码:




    

Java代码:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "leo";

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

    public void leoClick(View view) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this); //androidx.appcompat.app.AlertDialog;
        builder.setIcon(R.mipmap.ic_launcher)
                .setTitle("对话框")
                .setMessage("今天天气怎么样?")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        Log.e(TAG, "点击了确定按钮");
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        Log.e(TAG, "点击了取消按钮");
                    }
                })
                .setNeutralButton("中间/其他", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        Log.e(TAG, "点击了中间/其他按钮");
                    }
                })
                .create()
                .show(); //最后两个位置不能交换
    }
}

运行效果图1(无setView()):

 dialog_view.xml代码:




    

    

 运行效果2:

2.9 PopupWindow(悬浮框)

2.9.1 常用方法

  • setContentView(View contentView):设置PopupWindow显示的view
  • showAsDropDown(View anchor):相对某个控件的位置〈正左下方),无偏移showAsDropDown(View anchor, int xoff, int yoff):相对某个控件的位置,有偏移
  • setFocusable(boolean focusable):设置是否获取焦点
  • setBackgroundDrawable(Drawable background):设置背景dismiss()关闭弹窗
  • setAnimationStyle(int animationStyle):设置加载动画
  • setTouchable(boolean touchable):设置触摸使能
  • setOutsideTouchable(boolean touchable):设置PopupWindow外面的触摸使能

更多详见:2.6.1 PopupWindow(悬浮框)的基本使用 | 菜鸟教程 (runoob.com)

XML代码:




    

popup_view.xml代码: 




    

Java代码:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "leo";

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

    public void leoClick(View view) {
        View popupView = getLayoutInflater().inflate(R.layout.popup_view, null);
        //视图、宽、高、是否获取焦点(点击空白处取消)
        PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        popupWindow.setBackgroundDrawable(getResources().getDrawable(R.drawable.ceshi)); //设置背景
        popupWindow.showAsDropDown(view, 50,0);
        Log.e(TAG, "leoClick: 111111");

        Button btn1 = popupView.findViewById(R.id.btn1);
        Button btn2 = popupView.findViewById(R.id.btn2);
        btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.e(TAG, "onClick: 按钮1被点击");
            }
        });
        btn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.e(TAG, "onClick: 按钮2被点击");
            }
        });
    }
}

运行结果图:

ListView(列表条目)

使用步骤:

  • Step 1:在布局文件中添加一个LisetView
  • Step 2:新建一个条目布局文件,这里为list_item.xml,在此文件中写好每一个条目的布局内容
  • Step 3:创建item对应的JavaBean
  • Step 4:创建待填充的数据data集合并添加数据
  • Step 5:创建辅助类Adapter(适配器)需继承BaseAdapter并实现其方法,这里命名为MyAdapter,此类中包含适配的数据和Context。实现getView的时候,需要创建View并将其返回,然后需要在此方法中通过view的findById获取list_item中的组件并填充内容
  • Step 6: 创建并初始化MyAdpter适配器,然后获取布局中的ListView,通过set方法将创建好的MyAdpter适配器复值给ListView的Adapter方法就可以完成了

 inflate()方法解析:

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
  • 第一个参数:要获取的布局文件,传入R.layout.xxx
  • 第二个参数:这个参数也是一个布局,是为第一个参数指定的父布局。
  • 第三个参数(如果第二个参数为null这个参数将失去作用)
    true:将第一个参数表示的布局添加到第二参数的布局中。
    false:不将第一个参数表示的布局添加到第二参数的布局中。
    既然不添加,那么为什么第二个参数不设置为null呢。
    不添加的话,这个函数就只剩下一个作用了,那就是获取布局,为了使第一个参数的宽高属性不失效,所以要为他指定一个父布局

更多详见:2.4.5 ListView简单实用 | 菜鸟教程 (runoob.com)

MyActivity.java:

public class MainActivity extends AppCompatActivity {

    private ArrayList data = new ArrayList();

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

        for (int i = 0; i < 20; i++) {
            Bean bean = new Bean("享学"+i);
            data.add(bean);
        }

        ListView listView = findViewById(R.id.lv);
        listView.setAdapter(new MyAdapter(data, this));
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView adapterView, View view, int i, long l) {
                Log.e("TAG", "onItemClick: " + i);
            }
        });
    }
}

Bean.java:

package com.example.mylistview;

public class Bean {
    private String name;

    public Bean(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

MyAdapter.java:

public class MyAdapter extends BaseAdapter {
    private ArrayList data;
    private Context context;

    public MyAdapter(ArrayList data, Context context) {
        this.data = data;
        this.context = context;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int i) {
        return data.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        if (view == null) {
            view = LayoutInflater.from(context).inflate(R.layout.list_item,viewGroup,false);
        }
        TextView tv = view.findViewById(R.id.tv);
        tv.setText(data.get(i).getName());
        Log.e("TAG", "getView: " + i);
        return view;
    }
}

activity_main.xml:




    

list_item.xml:




    

运行效果图: 

优化后的MyAdapter.java:即用viewHolder存储传过来的view,并为view绑定绑定上viewHolder对象

public class MyAdapter extends BaseAdapter {
    private ArrayList data;
    private Context context;

    public MyAdapter(ArrayList data, Context context) {
        this.data = data;
        this.context = context;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int i) {
        return data.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder;
        if (view == null) {
            viewHolder = new ViewHolder();
            view = LayoutInflater.from(context).inflate(R.layout.list_item,viewGroup,false);
            viewHolder.textView = view.findViewById(R.id.tv);
            view.setTag(viewHolder);
        } else{
            viewHolder = (ViewHolder) view.getTag();
        }
        viewHolder.textView.setText(data.get(i).getName());
        Log.e("TAG", "getView: " + i);
        return view;
    }
    
    public final class ViewHolder{
        TextView textView;
    }
}

RecyclerView(大量数据集合的列表)

1 什么是RecycylerView:

RecycylerView是support-v7包中的新组件,是一个强大的滑动组件,是一个增强版的ListView,与经典的ListView相比,同样拥
不仅可以实现和ListView同样的效果,还优化了ListView中存在的各种不足之处,这一点从它的名字Recyclerview即回收view也可以看出。ResyslerView 能够实现横向滚动,这是ListView所不能实现的

2 如何使用:

Step 1:添加RecycylerView的依赖:

Step 2:创建布局:

  • activity_main.xml
  • item.xml

Step 3:创建适配器:

  1. 创建适配器类继承RecyclerView.Adapter类,传入泛型为RecyclerView.ViewHolder的子类(第2点)。
  2. 创建内部类即RecyclerView.ViewHolder类的子类,并为其绑定item控件。
  3. 实现RecyclerView.Adapter类的相关方法(快捷键为Alt+Enter)。
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType);
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position);//为MyViewHolder绑定上数据
    public int getItemCount();//返回数据的条目数

Step 4:在MainActivity.java中使用RecyclerView:

  1. 获取RecyclerView对象 。
  2. 准备适配的数据 。
  3. 适配器实例化 。
  4. 设置LayoutManager布局方式。
  5. 设置Adapter 。

 MyActivity.java:

public class MainActivity extends AppCompatActivity {

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

        ArrayList data = new ArrayList();

        for (int i = 0; i < 20; i++) {
            Bean bean = new Bean("享学"+i);
            data.add(bean);
        }

        RecyclerView recyclerView = findViewById(R.id.rv);
        MyAdapter myAdapter = new MyAdapter(data, this);

        LinearLayoutManager manager = new LinearLayoutManager(this);
        manager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(manager);

        recyclerView.setAdapter(myAdapter);
    }
}

Bean.java:

public class Bean {
    private String name;

    public Bean(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

MyAdapter.java:

public class MyAdapter extends RecyclerView.Adapter {

    private ArrayList data;
    private Context context;

    public MyAdapter(ArrayList data, Context context) {
        this.data = data;
        this.context = context;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = View.inflate(context, R.layout.recycler_item, null);
        MyViewHolder myViewHolder = new MyViewHolder(view);
        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.textView.setText(data.get(position).getName());
    }

    @Override
    public int getItemCount() {
        return data==null?0:data.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder{
        TextView textView;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.tv);
        }
    }
}

activity_main.xml:




    

recycler_item.xml:




    

运行效果图:

RecyclerView的点击事件

RecyclerView并没有像ListView一样暴露出Item点击事件或者长按事件处理的api,也就是说使用RecyclerView时候,需要我们自己来实现Item的点击和长按等事件的处理。实现方法有多种:

  • 可以监听RecyclerView的Touch事件然后判断手势做相应的处理
  • 也可以在通过在绑定ViewHolder的时候设置监听,然后通过Apater回调出去

这里选择第二种方法,更加直观和简单。

思路为:
通过在适配器中设置一个包含onItemClick函数的接口,然后添加setOnItemClickListener方法用于接收用户创建的该接口的实现类对象,最后在onBindViewHolder函数中调用onItemClick方法执行用于传入的对象的onItemClick方法。

设置步骤:

  • Step 1:创建OnItemClickListener接口
        public interface OnItemClickListener{
            void onItemClick(View view, int position);
            void onItemLongClick(View view, int position);
        }
  • Step 2:添加setOnItemClickListener方法()
        public void setOnItemClickListener(OnItemClickListener listenser) {
            this.onItemClickListener = listener;
        }
  • Step 3:在onBindViewHolder中调用实现类对象的onItemClick函数,也可在MyAdapter.MyViewHolder中调用实现类对象的onItemClick函数
        //第1种实现方法
        @Override
        public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
            holder.textView.setText(data.get(position).getName());
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(final View v) {
                    if(onItemClickListener != null) {
                        int pos = holder.getLayoutPosition();
                        onItemClickListener.onItemClick(holder.itemView, pos);
                    }
                }
            });
    
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    if(onItemClickListener != null) {
                        int pos = holder.getLayoutPosition();
                        onItemClickListener.onItemLongClick(holder.itemView, pos);
                    }
                    //表示此事件已经消费,不会触发单击事件
                    return true;
                }
            });
        }
        //第2种实现方法
        public class MyViewHolder extends RecyclerView.ViewHolder{
            TextView textView;
            public MyViewHolder(@NonNull View itemView) {
                super(itemView);
                textView = itemView.findViewById(R.id.tv);
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        if(onItemClickListener != null) {
                            onItemClickListener.onItemClick(itemView, getLayoutPosition());
                        }
                    }
                });
                itemView.setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View view) {
                        if(onItemClickListener != null) {
                            onItemClickListener.onItemLongClick(itemView, getLayoutPosition());
                        }
                        return false;
                    }
                });
            }
        }

  • Step 5:调用setOnItemClickListener方法传入OnItemClickListener的实现类对象
            myAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
                @Override
                public void onItemClick(View view, int position) {
                    Log.e("TAG", "onItemClick: " + position);
                }
    
                @Override
                public void onItemLongClick(View view, int position) {
                    Log.e("TAG", "onLongItemClick: " + position);
                }
            });

MyAdapter.java的完整代码:

public class MyAdapter extends RecyclerView.Adapter {

    private ArrayList data;
    private Context context;

    public MyAdapter(ArrayList data, Context context) {
        this.data = data;
        this.context = context;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = View.inflate(context, R.layout.recycler_item, null);
        MyViewHolder myViewHolder = new MyViewHolder(view);
        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.textView.setText(data.get(position).getName());
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                if(onItemClickListener != null) {
                    int pos = holder.getLayoutPosition();
                    onItemClickListener.onItemClick(holder.itemView, pos);
                }
            }
        });

        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if(onItemClickListener != null) {
                    int pos = holder.getLayoutPosition();
                    onItemClickListener.onItemLongClick(holder.itemView, pos);
                }
                //表示此事件已经消费,不会触发单击事件
                return true;
            }
        });
    }

    @Override
    public int getItemCount() {
        return data==null?0:data.size();
    }

    public interface OnItemClickListener{
        void onItemClick(View view, int position);
        void onItemLongClick(View view, int position);
    }
    private OnItemClickListener onItemClickListener;
    public void setOnItemClickListener(MyAdapter.OnItemClickListener listener) {
        this.onItemClickListener = listener;
    }

    public class MyViewHolder extends RecyclerView.ViewHolder{
        TextView textView;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.tv);
//            itemView.setOnClickListener(new View.OnClickListener() {
//                @Override
//                public void onClick(View view) {
//                    if(onItemClickListener != null) {
//                        onItemClickListener.onItemClick(itemView, getLayoutPosition());
//                    }
//                }
//            });
//            itemView.setOnLongClickListener(new View.OnLongClickListener() {
//                @Override
//                public boolean onLongClick(View view) {
//                    if(onItemClickListener != null) {
//                        onItemClickListener.onItemLongClick(itemView, getLayoutPosition());
//                    }
//                    return false;
//                }
//            });
        }
    }
}

recycler_itme.xml:




    

运行效果图:

第3章 Android的布局方式

3.1 LinearLayout(线性布局)

3.1.1 常用属性

  • orientation:布局中组件的排列方式
  • gravity:控制组件所包含的子元素的对齐方式,可多个组合
  • layout_gravity:控制该组件在父容器里的对其方式
  • background:为该组件设置一个背景图片,或者是直接用颜色覆盖
  • divider:分割线(可以使用View来设置分割线的效果)
  • showDividers:设置分割线所在的位置,none(无),beginning(开始),end(结束),middle(每两个组件间)
  • dividerPadding:设置分割线的padding
  • layout_weight(权重):该属性是用来按比例划分剩余的区域,按控件的对齐方式

更多详见:2.2.1 LinearLayout(线性布局) | 菜鸟教程 (runoob.com)

XML代码:




    

    

    

    

运行效果图:

3.2 RelativeLayout(相对布局)

3.2.1 相对父容器定位

  • layout_alignParentLeft:左对齐
  • layout_alignParentRight:右对齐
  • layout_alignParentTop:顶部对齐
  • layout_alignParentBottom:底部对齐
  • layout_centerHorizontal:水平居中
  • layout_centerVertical:垂直居中
  • layout_centerInParent:中间位置
     

3.2.2 相对兄弟容器定位

  • layout_toLeftOf:放置于参考组件的左边
  • layout_toRightOf:放置于参考组件的右边
  • layout_above:放置于参考组件的上方
  • layout_below:放置于参考组件的下方
  • layout_alignTop:对齐参考组件的上边界
  • layout_alignBottom:对齐参考组件的下边界
  • layout_alignLeft:对齐参考组件的左边界
  • layout_alignRight:对齐参考组件的右边界

3.2.3 通用属性

margin设置组件与父容器的边距

  • layout_margin:上下左右偏移
  • layout_marginLeft:左边距
  • layout_marginRight:右边距
  • layout_marginTop:上边距
  • layout_margiBottom:下边距

padding设置组件与子容器的边距

  • layout_padding:上下左右偏移
  • layout_paddingLeft:左边距
  • layout_paddingRight:右边距
  • layout_paddingTop:上边距
  • layout_paddingBottom:下边距

更多