主要用于显示文本信息
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView" //给当前控件定义一个为唯一一个标识符
android:layout_width="match_parent" //和父布局一样
android:layout_height="wrap_content"//控件的大小刚刚好包含里面的内容
android:gravity="center"
// 指定文字的对齐方式 可选 top bottom start end center 等
// | 指定多值 文中 center 等同于 center_vertical|center_horizontal
android:text="This is TextView"/>
</LinearLayout>
TextView还有很多属性,需要的话前往阅读(太多属性还是建议直接百度想要的属性)
https://blog.csdn.net/lizijie7471619/article/details/51164564
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
…
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
//android中默认按钮上英文字母大写 上行代码保留原始文字内容
android:text="Button"/>
</LinearLayout>
小插曲:为button 的点击事件注册一个监听器
// 第一种函数式API注册监听器
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener{
//在此添加
}
}
}
//使用实现接口的方式注册监听器
class MainActivity : AppCompatActivity(), View.OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener(this)
}
override fun onClick(v: View?) {
when (v?.id){
R.id.button ->{
//在此添加
}
}
}
}
用于与用户交互的控件,允许用户在控件里输入和编辑内容,并且可以对这些内容进行处理。
<EditText
android:id="@+id/edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Type something here" //显示提示性文字
android:maxLines="2"/> //最大限度为两行不会拉伸
//配合button使用 将输入内容传到button的toase
class MainActivity : AppCompatActivity(), View.OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener(this)
}
override fun onClick(v: View?) {
when (v?.id){
R.id.button ->{
val inputText = edittext.text.toString()
Toast.makeText(this,inputText,Toast.LENGTH_SHORT).show()
}
}
}
}
在界面上展示图片的控件
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/img1" /> //用src属性给ImageView一张图片
//动态修改ImageView中的图片
override fun onClick(v: View?) {
when (v?.id){
R.id.button ->{
imageView.setImageResource(R.drawable.ic_launcher_background)
//利用ImageView的SetImageResource()方法 对imageView对象经行修改
}
}
}
在界面上显示一个进度条,表示程序正在加载一些数据
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
//设置成水平进度条
android:max="100" /> //进度条的最大值100
//利用getVisibility()方法判断进度条是否可见 显示与隐藏间切换
override fun onClick(v: View?) {
when (v?.id){
R.id.button ->{
if (progressBar.visibility == View.VISIBLE){
progressBar.visibility = View.GONE
}else{
progressBar.visibility = View.VISIBLE
}
}
}
}
//配合长进度条使用 每点击一次按钮 进度条进度加十 最大为100
override fun onClick(v: View?) {
when (v?.id){
R.id.button ->{
progressBar.progress = progressBar.progress + 10
}
}
}
}
提醒非常重要的内容或者警告信息
override fun onClick(v: View?) {
when (v?.id){
R.id.button ->{
AlertDialog.Builder(this).apply {
//AlertDialog.Builder()构建对话框
//在apply中为对话框设置标题 内容 可否使用Back键关闭对话框
setTitle("this is Dialog")
setMessage("something important.")
setCancelable(false)
setPositiveButton("ok"){
//确认的点击事件
dialog, which ->
}
setNegativeButton("Cancle"){
//取消的点击事件
dialog , which ->
}
show() //将对话框显示出来
}
}
}
}
又称线性布局, 有垂直和水平两种
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" //默认为horizontal还可以选vertical
//选择垂直和水平的值是都要注意控件是刚好包含内容还是和和父类匹配
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
layout_gravity: 决定按钮的位置
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:text="Button 1"/>
android:layout_weight: 允许我们使用比例的方式来指定控件的大小
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/input_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" //表示水平方向平分宽度
android:hint="Type something"/>
<Button
android:id="@+id/send"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" //表示水平方向平分宽度
android:text="Send" />
//文本和按钮weight的“1”“1”表示各占1/2
</LinearLayout>
layout_weight: 先求出总权重,和屏幕适配,每个控件的大小 = 总长 * 比例
又称相对布局(常用布局)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button1"
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/button2"
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/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="button 3"/>
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:text="button 4"/>
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:text="button 5"/>
</RelativeLayout>
效果图:
alignParentXXX :表示相对父类的位置
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/button3"
android:layout_toLeftOf="@+id/button3"
android:text="button 1"/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/button3"
android:layout_toRightOf="@+id/button3"
android:text="button 2"/>
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="button 3"/>
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/button3"
android:layout_toLeftOf="@+id/button3"
android:text="button 4"/>
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/button3"
android:layout_toRightOf="@+id/button3"
android:text="button 5"/>
</RelativeLayout>
效果图:
**layout_xxx="@+id/buttonx":**表示相对buttonx的相对位置
又称帧布局 所有的控件默认摆放在布局的左上角
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="This is TextView"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="Button"/>
</FrameLayout>
效果图:
其中,layout_gravity用法和LineaLayout的一样
所有的控件都是直接或者间接继承View的,所有的布局都是直接或者间接继承自ViewGroup的。
解决多个Activity采用同一个标题栏导致代码大量重复
<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/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:background="@drawable/title_bg"
android:text="Back"
android:textColor="#fff"/>
//定义一个back按钮 高宽恰好包住文本 文本颜色:白
<TextView
android:id="@+id/titleText"
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="#faf"
android:textSize="24dp"/>
<Button
android:id="@+id/titleEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:background="@drawable/title_bg"
android:text="Edit"
android:textColor="#faf"/>
//定义一个Edit按钮 高宽恰好包住文本 文本颜色白
</LinearLayout>
//activity_main中
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/title" />
//使用 include语句 引入标题栏
</LinearLayout>
//需要在MainActivity中隐藏自带的标题栏
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()
//调用getSupportActionBar() 获得ActionBar实例 在调用它的hide()方法 将标题栏隐藏
}
}
解决每个Activity中都需要重新注册返回按钮的点击事件之类的事
//activity_main中
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.uicustomviews.TitleLayout //在布局文件中添加自定义控件
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
//MainActivity 中
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide() // 隐藏系统自带的标题栏
}
}
class TitleLayout(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
init { //定义一个结构体 对标题栏布局进行动态加载
LayoutInflater.from(context).inflate(R.layout.title, this)
//LayoutInflater.from(context)构建一个LayoutInflate对象
//然后调用inflate方法 动态加载一个布局文件
//以下为按钮的点击事件注册
titleBack.setOnClickListener{
val activity = context as Activity
activity.finish()
//TitleLayout接受的context是一个Activity的实例 先将其转成Activity类型 调用当前的Activity的finish()销毁
}
titleEdit.setOnClickListener{
Toast.makeText(context,"You clicked Edit button",Toast.LENGTH_SHORT).show()
//定义一个Toast 文本为‘You clicked Edit button’
}
}
}
class MainActivity : AppCompatActivity() {
private val data = listOf("apple","banana","orange","watermelon","pear",
"grape","pineapple","strawberry","cherry","mango",
"apple","banana","orange","watermelon","pear",
"grape","pineapple","strawberry","cherry","mango")
//定义一个集合作为数据(数据可以在数据库中提取 可以网上下载 视情况而定)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//使用ArrayAdapter适配器将数据传给ListView
val adapter = ArrayAdapter<String> (this,android.R.layout.simple_list_item_1,data)
//ArrayAdapter<泛型> (Activity实例,ListView的子项布局的id,数据源)
listView.adapter = adapter //最后调用ListView的SetAdapter()方法,将构建好的适配器对象传递出去
}
}
使ListView的界面显示更丰富的内容
package com.example.testlistview
import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.ListView
import android.widget.TextView
import kotlinx.android.synthetic.main.activity_main.*
import java.text.FieldPosition
class MainActivity : AppCompatActivity() {
private val fruitList = ArrayList<Fruit>()
//创建一个ArrayList实例 在initFruit()传入数据
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initFruits() //该方法初始化水果数据
val adapter = FruitAdapter(this, R.layout.fruit_item, fruitList)
listView.adapter = adapter //注意这里的list是小写的l
}
private fun initFruits(){ //
repeat(2){
//repeat函数是kotlin中的一个标准函数
fruitList.add(Fruit("apple",R.drawable.apple_pic))
fruitList.add(Fruit("banana",R.drawable.banana_pic))
fruitList.add(Fruit("orange",R.drawable.orange_pic))
fruitList.add(Fruit("watermelon",R.drawable.watermelon_pic))
fruitList.add(Fruit("pear",R.drawable.pear_pic))
fruitList.add(Fruit("pineapple",R.drawable.pineapple_pic))
fruitList.add(Fruit("strawberry",R.drawable.strawberry_pic))
fruitList.add(Fruit("cherry",R.drawable.cherry_pic))
fruitList.add(Fruit("mango",R.drawable.mango_pic))
//将数据传入
}
}
}
class Fruit(val name:String,val imagedId:Int)
//定义一个实体类 name和imageid两个字段
class FruitAdapter(activity: Activity,val resourId:Int,data: List<Fruit>)
:ArrayAdapter<Fruit>(activity,resourId,data){
//创建FruitAdapter类(自定义适配器) 继承ArrayAdapter
//定义主构造函数 传递Activity实例 ListView 子项布局的id 和数据源
override fun getView(position: Int,convertView: View?,parent:ViewGroup):View{
val view = LayoutInflater.from(context).inflate(resourId,parent,false)
/*使用LayoutInflater加载布局 inflate接受三个参数
第一个 加载的布局文件id 第二个是给加载好的布局添加一个父布局
第三个指定成false 表示让父布局声明的layout属性失效
*/
val fruitImage:ImageView =view.findViewById(R.id.fruitName)
val fruitName :TextView = view.findViewById(R.id.fruitName)
val fruit = getItem(position)
if(fruit != null){
fruitImage.setImageResource(fruit.imagedId)
fruitName.text = fruit.name
}
return view
}
}
class FruitAdapter(activity: Activity,val resourceId:Int,data: List<Fruit>)
:ArrayAdapter<Fruit>(activity,resourceId,data){
override fun getView(position: Int,convertView: View?,parent:ViewGroup):View{
val view: View
//在getView中判断 convertView 提高效率
if (convertView == null) {
view = LayoutInflater.from(context).inflate(resourceId,parent,false)
}else{ view = convertView
}
val fruitImage: ImageView = view.findViewById(R.id.fruitImage)
val fruitName: TextView = view.findViewById(R.id.fruitName)
val fruit = getItem(position) //获取当前的Fruit实例
if (fruit != null){
fruitImage.setImageResource(fruit.imageId)
fruitName.text = fruit.name
}
return view
}
}
class FruitAdapter(activity: Activity,val resourceId:Int,data: List<Fruit>)
:ArrayAdapter<Fruit>(activity,resourceId,data){
inner class ViewHolder(val fruitImage: ImageView,val fruitName: TextView)
override fun getView(position: Int,convertView: View?,parent:ViewGroup):View{
val view: View
val viewHolder :ViewHolder
if (convertView == null) {
view = LayoutInflater.from(context).inflate(resourceId,parent,false)
val fruitImage: ImageView = view.findViewById(R.id.fruitImage)
val fruitName: TextView = view.findViewById(R.id.fruitName)
viewHolder = ViewHolder(fruitImage,fruitName)
view.tag = viewHolder
//创建一个ViewHolder对象 将控件的实例存放进去 最后用setTag()存储在view中
}else{
view = convertView
viewHolder = view.tag as ViewHolder
//调用getTag() 把ViewHolder重新取出
}
val fruit = getItem(position)
if (fruit != null){
viewHolder.fruitImage.setImageResource(fruit.imagedId)
viewHolder.fruitName.text = fruit.name
}
return view
}
}
class MainActivity : AppCompatActivity() {
private val fruitList = ArrayList<Fruit>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initFruits()
val adapter = FruitAdapter(this, R.layout.fruit_item, fruitList)
listView.adapter = adapter
listView.setOnItemClickListener{
//注册监听器 通过position参数判断用户点击的子项 四个参数 除了position 可以用_省略 不过位置不变
_, _, position, _ ->
val fruit = fruitList[position]
Toast.makeText(this,fruit.name,Toast.LENGTH_SHORT).show()
}
}
private fun initFruits(){ //
repeat(2){
//repeat函数是kotlin中的一个标准函数
fruitList.add(Fruit("apple",R.drawable.apple_pic))
fruitList.add(Fruit("banana",R.drawable.banana_pic))
fruitList.add(Fruit("orange",R.drawable.orange_pic))
fruitList.add(Fruit("watermelon",R.drawable.watermelon_pic))
fruitList.add(Fruit("pear",R.drawable.pear_pic))
fruitList.add(Fruit("pineapple",R.drawable.pineapple_pic))
fruitList.add(Fruit("strawberry",R.drawable.strawberry_pic))
fruitList.add(Fruit("cherry",R.drawable.cherry_pic))
fruitList.add(Fruit("mango",R.drawable.mango_pic))
}
}
}
升级版ListView
为了让所有版本的android都可以使用 需要添加RecycleView库的依赖,如图:
下面分别是activity_main FruitAdapter Fruit Mainactivity 的代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
package com.example.recyclerview
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
class FruitAdapter(val fruitList: List<Fruit>) : RecyclerView.Adapter<FruitAdapter.ViewHolder>() {
//新建一个FruitAdapter类 为RecycleView准备一个适配器
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val fruitImage: ImageView = view.findViewById(R.id.fruitImage)
val fruitName: TextView = view.findViewById(R.id.fruitName)
}
/重写onCreateViewHolder 用于创建ViewHolder的实例
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.fruit_item, parent, false)
return ViewHolder(view)
}
//重写onBindViewHolder 用于子项数据的赋值
override fun onBindViewHolder(holder: FruitAdapter.ViewHolder, position: Int) {
val fruit = fruitList[position]
holder.fruitImage.setImageResource(fruit.imageId)
holder.fruitName.text = fruit.name
}
override fun getItemCount() = fruitList.size
//用于告诉RecycleView数据一共有多少子项 直接返回数据源长度即可
}
package com.example.recyclerview
class Fruit(val name:String,val imageId:Int)
package com.example.recyclerview
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fruit_item.view.*
class MainActivity : AppCompatActivity() {
private val fruitList = ArrayList<Fruit>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initFruits() //初始化水果数据
val layoutManager = LinearLayoutManager(this)
//LinearLayoutManager是线性布局的意思 实现与ListView类似的效果
recyclerView.layoutManager = layoutManager
val adaper = FruitAdapter(fruitList)
//创建FruitAdapter实例 并且将水果数据传入FruitAdapter的构造函数中
recyclerView.adapter = adaper
}
private fun initFruits(){ //
repeat(2){
//repeat函数是kotlin中的一个标准函数
fruitList.add(Fruit("apple",R.drawable.apple_pic))
fruitList.add(Fruit("banana",R.drawable.banana_pic))
fruitList.add(Fruit("orange",R.drawable.orange_pic))
fruitList.add(Fruit("watermelon",R.drawable.watermelon_pic))
fruitList.add(Fruit("pear",R.drawable.pear_pic))
fruitList.add(Fruit("pineapple",R.drawable.pineapple_pic))
fruitList.add(Fruit("strawberry",R.drawable.strawberry_pic))
fruitList.add(Fruit("cherry",R.drawable.cherry_pic))
fruitList.add(Fruit("mango",R.drawable.mango_pic))
}
}
}
1.横向滚动
//fruit_item中:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="80dp"
android:layout_height="wrap_content">
//LinearLayout 改成垂直方向排列 宽度为80dp(更雅观 不然有大有大小)
<ImageView
android:id="@+id/fruitImage"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal" //设置为在布局中水平居中
android:layout_marginLeft="10dp"/> //为了让图片保持距离
<TextView
android:id="@+id/fruitName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"//设置为在布局中水平居中
android:layout_marginTop="10dp"/> //为了让图片保持距离
</LinearLayout>
//MainActivity中的部分文件:
class MainActivity : AppCompatActivity() {
private val fruitList = ArrayList<Fruit>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initFruits()
val layoutManager = LinearLayoutManager(this)
layoutManager.orientation = LinearLayoutManager.HORIZONTAL
//使用layoutManager的setOrientation() 让布局横向排列
recyclerView.layoutManager = layoutManager
val adaper = FruitAdapter(fruitList)
recyclerView.adapter = adaper
}
//适当修改 使得瀑布流布局更美观
<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/fruitImage"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="10dp"/>
<TextView
android:id="@+id/fruitName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left" //这里
android:layout_marginTop="10dp"/>
</LinearLayout>
//下面为MainActivity的代码:
class MainActivity : AppCompatActivity() {
private val fruitList = ArrayList<Fruit>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initFruits()
val layoutManager = StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL)
//创建一个StaggeredGridLayoutManager 该构造函数中 第一个参数用于指定布局的列数 第二个 用于指定布局的排列方式
recyclerView.layoutManager = layoutManager
val adaper = FruitAdapter(fruitList)
recyclerView.adapter = adaper
}
private fun initFruits(){ //
repeat(2){
//repeat函数是kotlin中的一个标准函数
/*为了显示瀑布流布局的效果 定义getRandomLengthString函数 调用Range对象的random()函数
来创造一个 随机数 使得各个水果的名字的长度随机增倍 且 差异较大*/
fruitList.add(Fruit(getRandomLengthString("apple"),R.drawable.apple_pic))
fruitList.add(Fruit(getRandomLengthString("banana"),R.drawable.banana_pic))
fruitList.add(Fruit(getRandomLengthString("orange"),R.drawable.orange_pic))
fruitList.add(Fruit(getRandomLengthString("watermelon"),R.drawable.watermelon_pic))
fruitList.add(Fruit(getRandomLengthString("pear"),R.drawable.pear_pic))
fruitList.add(Fruit(getRandomLengthString("pineapple"),R.drawable.pineapple_pic))
fruitList.add(Fruit(getRandomLengthString("strawberry"),R.drawable.strawberry_pic))
fruitList.add(Fruit(getRandomLengthString("cherry"),R.drawable.cherry_pic))
fruitList.add(Fruit(getRandomLengthString("mango"),R.drawable.mango_pic))
}
}
private fun getRandomLengthString(str:String):String {
val n = (1..20).random()
val builder = StringBuilder()
repeat(n) {
builder.append(str)
}
return builder.toString()
}
}
class FruitAdapter(val fruitList: List<Fruit>) : RecyclerView.Adapter<FruitAdapter.ViewHolder>() {
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val fruitImage: ImageView = view.findViewById(R.id.fruitImage)
val fruitName: TextView = view.findViewById(R.id.fruitName)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.fruit_item, parent, false)
// 创建一个viewHolder实例 然后对最外层布局(itemView)和imageView注册点击事件
val viewHolder = ViewHolder(view)
viewHolder.itemView.setOnClickListener{
val position = viewHolder.adapterPosition
val fruit = fruitList[position]
Toast.makeText(parent.context,"you clicked view ${fruit.name}",Toast.LENGTH_SHORT).show()
}
viewHolder.fruitImage.setOnClickListener{
val position = viewHolder.adapterPosition
val fruit = fruitList[position]
Toast.makeText(parent.context,"you clicked image ${fruit.name}",Toast.LENGTH_SHORT).show()
}
return viewHolder
}
override fun onBindViewHolder(holder: FruitAdapter.ViewHolder, position: Int) {
val fruit = fruitList[position]
holder.fruitImage.setImageResource(fruit.imageId)
holder.fruitName.text = fruit.name
}
override fun getItemCount() = fruitList.size
}
可以直接看以下链接:
https://www.jianshu.com/p/9fe0b3d9a1dd
上文中还是比较繁琐的 我的理解是:可以当成聊天气泡 你输入的字多 气泡越长或者越宽 然后你该做的就是锁定一个区域让它可以自动伸缩(只是你指定的区域可以,其他区域不行) 就像你气泡的边框一样
//activity_main文件中:
<?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"
android:background="#d8e0e8">
<android.recycleview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/inputText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Type somgthing here"
android:maxLines="2"/>
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send"/>
</LinearLayout>
</LinearLayout>
//创建Msg类:
package com.example.uibestpractice
class Msg(val content:String,val type:Int){
companion object{
const val TYPE_RECEIVED = 0
const val TYPE_SEND = 1
}
}
//msg_left_item文件中:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:background="@drawable/message_left">
<TextView
android:id="@+id/leftMsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#fff"/>
</LinearLayout>
</FrameLayout>
//msg_right_item文件中:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:background="@drawable/message_right">
<TextView
android:id="@+id/rightMsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:textColor="#1000"/>
</LinearLayout>
</FrameLayout>
//创建MsgAdapter类:
package com.example.uibestpractice
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.os.persistableBundleOf
import androidx.recyclerview.widget.RecyclerView
class MsgAdapter(val msgList: List<Msg>):RecyclerView.Adapter<RecyclerView.ViewHolder>() {
inner class LeftViewHolder(view:View):RecyclerView.ViewHolder(view){
val leftMsg : TextView = view.findViewById(R.id.leftMsg)
}
inner class RightViewHolder(view:View):RecyclerView.ViewHolder(view){
val rightMsg : TextView = view.findViewById(R.id.leftMsg)
}
override fun getItemViewType(position: Int): Int {
val msg = msgList[position]
return msg.type
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = if(viewType == Msg.TYPE_RECEIVED) {
val view = LayoutInflater.from(parent.context).inflate(R.layout.msg_left_item,parent,false)
LeftViewHolder(view)
}else{
val view = LayoutInflater.from(parent.context).inflate(R.layout.msg_right_item,parent,false)
RightViewHolder(view)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val msg = msgList[position]
when(holder){
is LeftViewHolder -> holder.leftMsg.text = msg.content
is RightViewHolder-> holder.rightMsg.text = msg.content
}
}
override fun getItemCount() = msgList.size
}
//MainActivity中:
//package com.example.uibestpractice
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() ,View.OnClickListener{
private val msgList = ArrayList<Msg>()
private var adapter: MsgAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initMsg()
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
adapter = MsgAdapter(msgList)
recyclerView.adapter = adapter
send.setOnClickListener(this)
}
override fun onClick(v: View?){
when(v){
send -> {
val content = inputText.text.toString()
if (content.isNotEmpty()){
val msg = Msg(content,Msg.TYPE_SEND)
msgList.add(msg)
adapter?.notifyItemInserted(msgList.size - 1 )
//当有新消息时 刷新RecyclerView中的显示
recyclerView.scrollToPosition(msgList.size - 1)
//将RecyclerView定位到最后一行
inputText.setText("")
//清空输入框中的内容
}
}
}
}
private fun initMsg(){
val msg1 = Msg("hello guy.",Msg.TYPE_RECEIVED)
msgList.add(msg1)
val msg2 = Msg("hello. who is that?",Msg.TYPE_SEND)
msgList.add(msg2)
val msg3 = Msg("This is Tom.Nice talking to you ",Msg.TYPE_RECEIVED)
msgList.add(msg3)
}
}
标准函数repeat:
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/repeat.html
感叹号前面为代码
#FFFFE0!–亮黄色 -->
#FFFF00!–黄色 -->
#FFFAFA!–雪白色 -->
#FFFAF0!–花白色 -->
#FFFACD!–柠檬绸色 -->
#FFF8DC!–米绸色 -->
#FFF5EE!–海贝色 -->
#FFF0F5!–淡紫红 -->
#FFEFD5!–番木色 -->
#FFEBCD!–白杏色 -->
#FFE4E1!–浅玫瑰色 -->
#FFE4C4!–桔黄色 -->
#FFE4B5!–鹿皮色 -->
#FFDEAD!–纳瓦白 -->
#FFDAB9!–桃色 -->
#FFD700!–金色 -->
#FFC0CB!–粉红色 -->
#FFB6C1!–亮粉红色 -->
#FFA500!–橙色 -->
#FFA07A!–亮肉色 -->
#FF8C00!–暗桔黄色 -->
#FF7F50!–珊瑚色 -->
#FF69B4!–热粉红色 -->
#FF6347!–西红柿色 -->
#FF4500!–红橙色 -->
#FF1493!–深粉红色 -->
#FF00FF
#FF00FF!–红紫色 -->
#FF0000–红色 -->
以下是一些个人在学习过程中的经验或者说犯的错误
1.
//activity_main文件
<?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" /> //*** 这里只用了引入布局再使用自定义控件的方法 会使得按件无反应 应该删去引入布局的部分
<com.example.uicustomviews.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>