文章目录
- 0. 前言碎碎念
- 1. 实现自定义复合组件效果
- 1.1创建复合组件
- 1.2 Activity中实现功能
- 1.3 自定义控件实现制定组件的逻辑交互
- 1.3.1 创建控件并绑定自定义组件
- 1.3.2 实现交互逻辑
- 2. 进阶ListView
- 2.1 内置布局方式基础使用
- 2.2 自定义布局方式
0. 前言碎碎念
安卓开发这些组件用来用去搞得人头都大了,一会儿xml一会儿View一会儿又是ViewGroup的。
在这里留个档,以防未来自己又忘了。
现在我所熟知的组件比如按钮、文本框、编辑框、乃至图片组件,他们本质上都是一种view,追溯到最上层,他们都继承了View。
常用的一些布局都是继承自ViewGroup的,而继承自ViewGroup的这种特殊的View可以容纳其他的View组件,从而形成“复合版本”的View,这种符合版本的View本身又可以直接作为一个新的组件被加入到其他布局中,使用如下这种形式即可调用包含:
<include layout="@layout/布局xml文件名">
但是,上述调用只能将复合组件(SubXml)加入另一个布局(MainXml)里面,但是复合组件里面的子组件无法互动。
为什么呢?因为组件只是显示了出来,他后面并没有逻辑代码来支撑他们。
我们当然可以在MainActivity中通过findViewById()来找到对应的组件并为其设置逻辑行为代码比如监听点击或者其他的行为。
但这样就显得很臃肿了,我们想要的效果是:
- 自己定义一个复合组件
- 这个组件可以直接被包含复用
- 这个组件自带交互效果,不需要调用者自己再实现
现在的问题就是,我该如何实现组件的的交互效果.
1. 实现自定义复合组件效果
1.1创建复合组件
//layout_sub.xml<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/cardview_dark_background"><Buttonandroid:id="@+id/titleBack"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="5dp"android:text="BACK"/><TextViewandroid:id="@+id/titleText"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:layout_gravity="center"android:text="Title Text"android:textColor="@color/white"android:textSize="24sp"/><Buttonandroid:id="@+id/titleEdit"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="5dp"android:text="EDIT"/></LinearLayout>样式如下所示:
在主布局中调用:
//layout_main.xml<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:fitsSystemWindows="true"><includelayout="@layout/layout_sub"/></LinearLayout>运行看效果:
1.2 Activity中实现功能
//MainActivity.ktclassMainActivity:AppCompatActivity(){overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)findViewById<Button>(R.id.titleBack).setOnClickListener{finish()}findViewById<Button>(R.id.titleEdit).setOnClickListener{Toast.makeText(this,"你点击了EDIT按钮",Toast.LENGTH_LONG).show()}}}在调用者的内部通过findViewById()来实现交互逻辑显得实在有些low,并且对于复合组件的复用也很不方便,因为复合组件的每一个子组件的功能在创建的时候就已经决定了,但现在无论谁调用它都需要重复编写交互逻辑,重复劳动太多了。
事实上,上面那个xml文件说是复合组件,实际上它连复合组件都不算,
因为它只是一个将三个View组件放在一起的一个普通xml文件罢了,
我们引用它的方式也仅仅只是include,就像php那样,只是占了个位置,相当于将它内部的组件给放到了这里。
我们可以说它是视觉上的复合组件,这是没问题的。
但它还绝对算不上说是逻辑交互上的复合组件。
1.3 自定义控件实现制定组件的逻辑交互
1.3.1 创建控件并绑定自定义组件
前言部分我说过,自定义控件实际上是一个继承了ViewGroup的layout布局,那么是不是说,只要我有一个layout布局并将其引入到layout_main.xml中就能实现一样的效果,甚至还能拥有自己内置好的交互逻辑?
答案是肯定的。
直接自定义一个类,并使其继承LinearLayout类,那么这个类就是一个layout布局了。
令人疑惑的是:这不就是一个继承了LinearLayout布局的类吗?为什么他也是一个布局?
我的回答是不必知道,只需要知道继承了LinearLayout布局的类可以作为“代理”来实现复合组件的交互逻辑就行。
光有这个类可不行,他还没和复合组件建立起任何联系呢。
classTitleLayout(context:Context,attrs:AttributeSet):LinearLayout(context){init{LayoutInflater.from(context).inflate(R.layout.layout_sub,this)}}不要看其他地方,关注inflate(R.layout.layout_sub,this),这个方法就是将this也就是当前这个类,和我创建的复合组件xml文件链接在一起,相当于这个类就是这个复合组件了,这个类我将其称之为控件类,因为它不仅仅是组件了,后面还会有逻辑交互能力。这个时候,layout_sub才真正成为了一个View,一个真正的自定义的复合组件,而不仅仅是几个组件的集合。
那么,这个context是哪里来的呢?答案是,哪个Activity调用这个控件,这个context上下文就属于哪个Activity。
LayoutInflater就是用来将xml文件转换成一种View的
attrs又是啥呢?它是父属性的集合,也就是调用这个控件处指定的属性,后面会看到的。
将上下文传给LinearLayout类,这个就不必提了。
1.3.2 实现交互逻辑
添加代码:
classTitleLayout(context:Context,attrs:AttributeSet):LinearLayout(context){init{LayoutInflater.from(context).inflate(R.layout.layout_sub,this)findViewById<Button>(R.id.titleBack).setOnClickListener{valactivity=contextasActivity activity.finish()}findViewById<Button>(R.id.titleEdit).setOnClickListener{Toast.makeText(context,"你点击了EDIT按钮",Toast.LENGTH_LONG).show()}}}修改引用方式:
//activity_main.xml<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:fitsSystemWindows="true"><com.bignerdranch.android.recyclerview.TitleLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"/></LinearLayout>这种引用方式才是View引用,而不仅仅是include了
2. 进阶ListView
2.1 内置布局方式基础使用
引入的方式很简单,直接使用ListView组件即可,和其他的组件比如Button、TextView没什么区别。
//activity_main.xml<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:fitsSystemWindows="true"><ListViewandroid:id="@+id/listView"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout>嗯,如果只是想展示数据,那就在Activity中定义数据集合,然后使用ArrayAdapter创建一个适配器
val adapter = ArrayAdapter< String >(this, android.R.layout.simple_list_item_1, data)
这句使用ArrayAdapter创建了一个适配器,将《子项布局方式》和数据放在一起并绑定到this这个Activity中。
然后再通过find找到组件并将组件的adapter属性设为上面创建的adapter。
classMainActivity:AppCompatActivity(){privatevaldata=arrayListOf("abc","dhfi","hdfk","abc","dhfi","hdfk","abc","dhfi","hdfk","abc","dhfi","hdfk","dhfi","hdfk","abc","dhfi","hdfk","abc","dhfi","hdfk")overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)valadapter=ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,data)findViewById<ListView>(R.id.listView).adapter=adapter}}2.2 自定义布局方式
这就要用到第一节的知识了,自定义复合组件,实现更为自由的显示方式,不过值得注意的是,我们创建的复合组件只是一个子项目(item)的布局,而不是一整个屏幕的布局。
代码不写了,你到时候看应该能懂我意思,总之创建一个图片+文字描述的布局xml文件,限制图片长宽防止显示不一致,文字部分wrap_content即可。
关键就在于这个adapter该怎么办,最后是要设置ListView的adapter属性的,所以需要一个adapter
随便写一个类就能作为adapter么?那当然不是,还是需要继承ArrayAdapter的,继承ArrayAdapter之后,其实还是不能用的,需要重写getView方法,为什么?因为要自定义布局方式。
回看2.1,要将item的布局和this结合起来,所以我们需要这个getView来生成View,也就是将前面提到的xml文件转为View。
但我们是要自定义布局方式的,系统其实并不知道我们要怎么
不写了草,这啥b安卓怎么这么难理解,滚吧