RecyclerView:
分为两部分:
1.适配器:
创建一个类继承于RecyclerView.Adapter类
①条目集:
在layout文件下面创建一个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="50dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_fruit"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_margin="10dp" />
<TextView
android:id="@+id/tv_fruit"
android:layout_width="70dp"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:padding="5dp" />
</LinearLayout>
②适配器类的编写
创建一个RecyclerView继承于RecyclerView.Adapter,将方法重写,重点在于onCreateViewHolder方法的编写,这个方法主要完成创建ViewHolder的任务,在这个方法里面我们将条目的布局引入,创建一个ViewHolder的实例,将加载出来的布局传入到 构造函数里面,
onBindViewHolder此方法用于对RecyclerView子项数据进行赋值,每个子项被滚动到屏幕里,都会被执行,
getItemCount方法最简单,是用于返回数据源的长度。
这里使用了ViewHolder机制
ViewHolder模式的核心思想是在列表项视图的布局中,使用一个内部类来持有视图控件的引用,以避免重复查找视图的成本。这个内部类通常被命名为
ViewHolder
。
- 在适配器的
getView
或onCreateViewHolder
方法中,可以使用ViewHolder来查找并持有视图控件的引用。- 如果视图已经被创建并持有了控件引用,那么就可以直接使用它们,而不需要重复查找。
这个是用于持有对控件的引用,对于convertView还有一个是减少对控件的生成,防止内存溢出
最后,数据和控件的绑定在onBindViuViewHolder方法,将由onCreateViewHolder方法传来的holder向下转型为继承RecyclerViewAdapter.ViewHolder类的内部类ViewHolder,
package com.example.newhighview.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.newhighview.R;
import com.example.newhighview.bean.Fruit;
import java.util.List;
public class RecyclerViewAdapter extends RecyclerView.Adapter {
private ViewHolder holder;
static class ViewHolder extends RecyclerView.ViewHolder {
TextView tv;
ImageView iv;
public ViewHolder(View view) {
super(view);
tv = view.findViewById(R.id.tv_fruit);
iv = view.findViewById(R.id.iv_fruit);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_fruit, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
private List list;
public RecyclerViewAdapter(List list) {
this.list = list;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
Fruit fruit = (Fruit) list.get(position);
ViewHolder v = (RecyclerViewAdapter.ViewHolder) holder;
v.tv.setText(fruit.getTextDesc());
v.iv.setImageResource(fruit.getPicNum());
}
@Override
public int getItemCount() {
return list.size();
}
}
2.实体类:
目的:将每一个条目上的控件作为类的元素,包装成一个类,
由于场景的不同,我们的数据可能来自其他地方,或者已经获取,这里数据已经知道,直接一个for循环放在list集合里面,集合里每一个元素都对应一个条目,需要的数据。
package com.example.newhighview.bean;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.newhighview.R;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Fruit {
public Fruit() {
}
private int picNum;
private String textDesc;
public static final int[] picNum1 = new int[]{R.drawable.image1, R.drawable.image2, R.drawable.image3, R.drawable.image4, R.drawable.image5, R.drawable.image6,};
public static final String[] textDesc1 = new String[]{"这是芒果", "这是苹果", "这是葡萄", "这是火龙果", "这是西瓜", "这是香蕉"};
static List<Fruit> list;
public Fruit(int picNum, String textDesc) {
this.picNum = picNum;
this.textDesc = textDesc;
}
public int getPicNum() {
return picNum;
}
public static List<Fruit> getDefaultList() {
if (list == null) {
list = new ArrayList<>();
}
//将fruit直接打包成对象
for (int i = 0; i < picNum1.length; i++) {
list.add(new Fruit(picNum1[i], textDesc1[i]));
}
return list;
}
public void setPicNum(int picNum) {
this.picNum = picNum;
}
public String getTextDesc() {
return textDesc;
}
public void setTextDesc(String textDesc) {
this.textDesc = textDesc;
}
}
以上两部分完成之后,在活动里,创建LinearLayoutManager类的实例,并传输本活动的的上下文,,并将它设置到recyclerView里面去。
package com.example.newhighview;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import com.example.newhighview.adapter.RecyclerViewAdapter;
import com.example.newhighview.bean.Fruit;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.Rv);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
RecyclerViewAdapter r = new RecyclerViewAdapter(Fruit.getDefaultList());
recyclerView.setAdapter(r);
}
}
记得设置适配器。
listView:
和RecyclerView类似,也是用来显示大量数据项的。
listView和RecyclerView在实体类的代码编写上,没有什么区别,应用实际场景决定数据怎么设置,这里我们数据还是那些。
listView适配器:
我们继承BaseAdapter适配器,重写方法,
注意适配器最重要的作用:
使数据源和条目进行匹配
getView:用来进行绑定数据和条目里的控件,也是ViewHolder派上作用的地方
getCount:返回条目总数
getItem:返回当前条目
getItemId:返回当前条目的个数
我们着重来说getView方法,中代码的编写,
首先通过LayoutInflater类将布局转化为对象,返回对象是一个view
View view = LayoutInflater.from(context).inflate(R.layout.item_fruit, null);
通过这个view调用findViewById找到控件,然后通过操作list集合,将数据和控件绑定起来
tv = convertView.findViewById(R.id.tv_fruit);
iv = convertView.findViewById(R.id.iv_fruit);
tv.setText(((Fruit) l.get(position)).getTextDesc());
iv.setImageResource(((Fruit) l.get(position)).getPicNum());
但是这样做有个弊端,如果条目很少,可以在这样做,每出现一个条目,就创建那一套控件的对象。会浪费很大的资源。
因此我们使用一个巧妙的办法,结合ViewHolder模式,使用convertView。
convertView
是在 Android 中使用适配器(Adapter)填充ListView
或RecyclerView
等列表控件时经常使用的一个概念。它是一个用于重用已创建的列表项视图的参数或变量,旨在提高性能和减少内存消耗。具体来说,
convertView
是在getView
方法(对于ListView
)或onCreateViewHolder
方法(对于RecyclerView
)中用于缓存已经创建的列表项视图的参数。它代表着当前正在处理的列表项视图,这个视图可能已经被创建和绘制,也可能是一个可重用的视图,取决于它是否为空。在适配器中,你可以使用
convertView
来检查是否有可重用的视图可供使用,如果有,你可以直接将数据绑定到它上面,而不是重新创建一个新的视图。这可以显著提高列表控件的性能,尤其是在大型列表中。
基本用法:
- 在
getView
方法或onCreateViewHolder
方法中,检查convertView
是否为空。 - 如果
convertView
为空,表示没有可重用的视图,你需要创建一个新的视图并将视图控件的引用存储在一个 ViewHolder 对象中,并将 ViewHolder 对象存储在convertView
的标签中以备后用。 - 如果
convertView
不为空,表示有可重用的视图,你可以从中获取 ViewHolder 对象,并使用它来设置数据。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
//如果不为空,则说明没有可用的视图,需要创建新的视图
convertView = LayoutInflater.from(context).inflate(R.layout.item_fruit, null);
vh = new ViewHolder();
tv = convertView.findViewById(R.id.tv_fruit);
iv = convertView.findViewById(R.id.iv_fruit);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
tv.setText(((Fruit) l.get(position)).getTextDesc());
iv.setImageResource(((Fruit) l.get(position)).getPicNum());
return convertView;
}
对于长列表可以大大提高性能。
在活动中:
不需要布局管理器,直接将适配器设置给listview
注意:
对于listView有一个无法设置条目高度和宽度的问题,这和 RecyclerView有区别,RecyclerView可以直接在条目的根布局上设置条目的高。需要直接设置内部控件的高度,或者重新在原有布局的情况下,设置一个新的布局。
Spinner:
Sipnner指的是下拉列表,
有两种模式:分别是dialog和dropdown
适配器和前面没有区别,使用dropdown模式时候,记得还要重写getDropDwonView方法
ToolBar:
其实就是标题栏,系统默认的是ActionBar,现在我们将它替换为ToolBar,
在theme文件中修改:
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.ActivityTest" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">#0080ff</item>
<item name="colorPrimaryVariant">#0080ff</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>
注意第二行代码,修改为了NoActionBar,此时系统默认的标题栏就消失了,此时,我们重新搞一个toolbar,
创建menu目录,创建menu resouerce file,
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/backup"
android:icon="@android:drawable/ic_menu_upload_you_tube"
android:title="Backup"
app:showAsAction="always" />
<item
android:id="@+id/Delete"
android:icon="@android:drawable/ic_menu_delete"
android:title="Delete"
app:showAsAction="ifRoom" />
<item
android:id="@+id/settings"
android:icon="@android:drawable/ic_menu_add"
android:title="settings"
app:showAsAction="never" />
</menu>
在安卓开发中,showAsAction属性是用于控制菜单项在Action Bar中的显示行为的。Action Bar是Android应用程序中的一个标准界面元素,它通常出现在应用程序的顶部,提供了一个包含应用程序名称、选项菜单和导航按钮的区域。
showAsAction属性可以接受不同的值,用于指定菜单项在Action Bar中的显示方式。以下是showAsAction属性可以接受的值:
- alaways:这个值会使菜单项一直显示在ActionBar上。
- ifRoom:如果有足够的空间,这个值会使菜单显示在ActionBar上。
- never:这个值菜单永远不会出现在ActionBar是。
- withText:这个值使菜单和它的图标、菜单文本一起显示。
例如,如果要将一个名为“文件(F)”的菜单项始终显示在Action Bar上,可以将它的showAsAction属性设置为“always”。如果希望将一个名为“编辑(E)”的菜单项永远不会在Action Bar中显示,可以将它的showAsAction属性设置为“never”。
需要注意的是,showAsAction属性是仅在应用程序目标设为蜂巢平台(即Android 3.0)或更高版本时才有效。在较早版本的Android平台上,菜单项需要在选项菜单中手动添加和显示。
活动的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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="com.example.toolBar.MainActivity">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:id="@+id/tb"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</FrameLayout>
活动:
package com.example.toolBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.os.Bundle;
import android.view.Menu;
import com.example.newhighview.R;
public class MainActivity extends AppCompatActivity {
private Toolbar tb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
tb = findViewById(R.id.tb);
setSupportActionBar(tb);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar, menu);
return true;
}
}
将这些菜单显示出来,
DrawerLayout:
滑动菜单:
这是一种布局,
布局中允许放进去两个直接子控件,第一个子控件是主屏幕显示的内容,第二个子控件显示的是滑动菜单中显示的内容。
因此:
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#00ff80"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</FrameLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#fff"
android:text="This is menu"
android:textSize="30sp" />
</androidx.drawerlayout.widget.DrawerLayout>
注意:
其中第二个子空间
layout_gravity属性必须有,而且是start。
关于FrameLayout:
FrameLayout是Android布局中的一种,它是一种简单的布局,通常用于堆叠视图。在FrameLayout中,所有的子视图都被钉在屏幕左上角,这也意味着所有的子视图都被堆叠在一起。
如果你需要更改视图的位置,你可以使用
layout_gravity
属性。这个属性接受以下值:top
、bottom
、left
、right
、center_vertical
、center_horizontal
、center
等。举个例子,以下是一个FrameLayout的使用:
<FrameLayout
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:text="Button 1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 2"
android:layout_gravity="center" />
</FrameLayout>
在这个例子中,两个按钮都放在FrameLayout中。第一个按钮(Button 1)默认被放在左上角,而第二个按钮(Button 2)则被放在屏幕中心,因为我们使用了
layout_gravity="center"
。