Android入门(九)| 滚动控件 ListView 与 RecyclerView

文章目录

  • ListView
    • 内置类型的简单运用
    • 定制数据类型
    • 提升效率
    • 点击事件
  • RecyclerView
    • 布局管理器
    • 点击事件


ListView

内置类型的简单运用

由于手机屏幕空间有限,能够一次性在屏幕上显示的内容不多,当我们的程序有大量数据需要显示的时候就可以借助 ListView 来实现。

布局文件 listview_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><ListViewandroid:id="@+id/list_view"android:layout_width="match_parent"android:layout_height="match_parent" /></androidx.constraintlayout.widget.ConstraintLayout>

活动文件 ListViewTest.java

public class ListViewTest extends AppCompatActivity {private String[] data = {"Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry","Cherry", "Mango","Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry","Cherry","Mango"};// 数据无法直接传递给 ListView@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.listview_layout);ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data);// 借助适配器传递数据ListView listView = (ListView)findViewById(R.id.list_view);listView.setAdapter(adapter);}
}
  • ListView 子项布局的 idandroid.R.layout.simple_list_item_1 ,其是一个 Android 内置的布局文件,内容只有一个 TextView,可以用于简单地显示一段文本。
  • ArrayAdapter 构造函数
    1. 参数一:当前 Context
    2. 参数二:ListView 子项布局的 id,此例中为上面提到的 TextView
    3. 参数三:适配布局的数据

运行结果:

在这里插入图片描述


定制数据类型

如果想要每个水果的名字都对应一张图片,那么内置的 String 类型就无法满足需求了,因此需要自定义一个 Fruit 类:

package com.example.activitytest;public class Fruit {private String name;private int imageId;public Fruit(String name, int imageId){this.name = name;this.imageId = imageId;}public String getName(){return name;}public int getImageId(){return imageId;}
}

ListView 的子项指定一个自定义布局,在 layout 目录下新建 fruit_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"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageViewandroid:id="@+id/fruit_image"android:layout_width="300dp"android:layout_height="200dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintVertical_bias="0.0" /><TextViewandroid:id="@+id/fruit_name"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="@+id/fruit_image"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/fruit_image" /></androidx.constraintlayout.widget.ConstraintLayout>
  • ImageView:显示图片。
  • TextView :显式名称,文字居中。

接下来参考书上的内容创建一个自定义适配器:

public class FruitAdapter extends ArrayAdapter<Fruit> {private List<Fruit> fruitList; // 数据private int resourceId; // 子项xml布局文件public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects){super(context, textViewResourceId, objects);resourceId = textViewResourceId;fruitList = objects;}// 重写getView方法,加载每个处于屏幕内的子项时调用public View getView(int position, View convertView, ViewGroup parent){Fruit fruit = getItem(position); // 获取当前的 Fruit 实例,还有一种写法:fruitList.get(position),从list中获取单个节点元素View view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);fruitImage.setImageResource(fruit.getImageId());TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);fruitName.setText(fruitList.get(position).getName());return view;}
}

构造函数 FruitAdapter 本质上还是雷同于被它 extendsArrayAdapter构造函数,参数分析:

  • context:指定当前上下文。
  • textViewResourceIdListView 子项布局的 id
  • objects:适配布局的数据

加载每个处于屏幕内的子项时调用的 getView,由于我们是重写已有函数,因此参数是固定的:

  • position:当前 Item 在屏幕中的位置,通常搭配 getItem() 返回一个子View以获取当前实例。
  • convertView:缓存视图 View,如果非null,则直接再次对 convertView 复用,否则才创建新的 View。
  • parent:Item 的 View 的父视图,用处的话私以为就是为了充当 inflate 的第二个参数。

LayoutInflater 是根据 Layout XML文件 来生成 对应 View 对象 的系统服务。一般用它之作一件事: inflate(加载布局)。

inflate 方法:

public View inflate (int resource, ViewGroup root, boolean attachToRoot) 
  • resource:要加载的布局对应的资源 id
  • root:在参数一对应布局外部嵌套一个父布局,如果不需要则为 null。
  • attachToRoot:是否为加载的布局添加一个 root 的外层容器
    1. 为 true 时将子布局添加到父布局中并保存子布局的 layout 配置
    2. 为 false 时表示只让在子布局中声明的 layout 属性生效,但不将子布局添加到父布局中,此时想要将子布局添加到父布局中需要调用 addView() 方法。

上述代码中参数三就被赋值为 false,这是因为 ListView 继承自 AdapterView,继承了 AdapterView 的控件是不支持 AddView() 方法的,因为一旦 resource 对应的 View 有了父布局,就不能再被添加到 ListView 中了。而参数三为 true 时会自动调用 AddView() 方法(关于inflate参数的相关信息详见本文)。

// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) { // attachToRoot 为 true 时自动调用 addView 方法root.addView(temp, params);
}

在这里插入图片描述

关于 LayoutInflater 与 inflate 可参考本文。

设置显示的图片和文字

  • 通过 findViewById 方法分别获取到 ImagViewTextView 的实例
  • 分别调用它们的 setImageResourcesetText 方法来设置显示的图片和文字
  • 最后将布局返回

最后修改活动文件 ListViewTest.java ,以自定义适配器为 extends ArrayAdapter<Fruit> 的情况为例:

public class ListViewTest extends AppCompatActivity {private List<Fruit> fruitList = new ArrayList<>();@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.listview_layout);initFruits(); // 初始化数据集// 借助适配器传递数据FruitAdapter adapter = new FruitAdapter(this, R.layout.fruit_item, fruitList);// FruitAdapter adapter = new FruitAdapter(this, fruitList);ListView listView = (ListView)findViewById(R.id.list_view);listView.setAdapter(adapter);}private void initFruits(){Fruit apple = new Fruit("Apple", R.drawable.ic_launcher_background);fruitList.add(apple);Fruit banana = new Fruit("Banana", R.drawable.ic_launcher_foreground);fruitList.add(banana);Fruit orange = new Fruit("Orange", R.drawable.cmy1);fruitList.add(orange);Fruit Watermelon = new Fruit("Watermelon", R.drawable.cmy2);fruitList.add(Watermelon);Fruit pear = new Fruit("Pear", R.drawable.cmy3);fruitList.add(pear);Fruit grape = new Fruit("Grape", R.drawable.cmy4);fruitList.add(grape);}
}

提升效率

  • FruitAdaptergetView 方法中每次都通过 LayoutInflaterinflate 将布局重新加载了一遍, 当 ListView 快速滚动的时候就会成为性能的瓶颈。而之前提到 getView 方法中的 convertView 参数可以缓存 View,因此可以利用该参数来提高效率。
  • getView 方法中我们每次都要通过 findViewById 方法创建控件 fruit_imagefruit_name 的实例。不如用一个 内部类ViewHolder 来对控件实例进行缓存。
	public View getView(int position, View convertView, ViewGroup parent){Fruit fruit = (Fruit) getItem(position);ViewHolder viewHolder;if(convertView == null){convertView = LayoutInflater.from(context).inflate(resourceId, parent, false);viewHolder = new ViewHolder();viewHolder.fruitImage = convertView.findViewById(R.id.fruit_image);viewHolder.fruitName = convertView.findViewById(R.id.fruit_name);convertView.setTag(viewHolder);}else{viewHolder = (ViewHolder) convertView.getTag();}viewHolder.fruitImage.setImageResource(fruit.getImageId());viewHolder.fruitName.setText(fruit.getName());return convertView;}class ViewHolder{ImageView fruitImage;TextView fruitName;}

总而言之,之前每次加载屏幕外的 子项 时都需要进行前文提到的两种操作,但在进行改进之后,只有第一次加载(比如往下滑屏幕)的时候执行 convertView == null 的代码才需进行前文的两项操作,之后加载时(比如滑到底了再往上滑)就是 convertView 非空的情况了。


点击事件

滚动只是视觉效果,子项还可以点击。修改活动文件 ListViewTest.java

    protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.listview_layout);initFruits();FruitAdapter adapter = new FruitAdapter(this, R.layout.fruit_item, fruitList);// FruitAdapter adapter = new FruitAdapter(this, fruitList);// 借助适配器传递数据ListView listView = (ListView)findViewById(R.id.list_view);listView.setAdapter(adapter);listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {Fruit fruit = fruitList.get(position);Toast.makeText(ListViewTest.this, fruit.getName(), Toast.LENGTH_SHORT).show();}});/* lambda表达式代替内联函数listView.setOnItemClickListener((AdapterView<?> parent, View view, int position, long id)->{Fruit fruit = fruitList.get(position);Toast.makeText(ListViewTest.this, fruit.getName(), Toast.LENGTH_SHORT).show();});*/}
  • 使用 setOnItemClickListener 方法为 ListView 注册了一个监听器
  • 点击任何一个子项时回调 onItemClick 方法,通过 position 参数获得点击的是哪一个子项
  • 获取相应 Fruit 名称并通过 Toast 输出

RecyclerView

布局管理器

ListView性能容易变差、数据只能纵向滚动 的缺点。而 RecyclerView 就支持横向滚动。

为了让所有 Android 版本都能使用,RecyclerView 被定义在 support 库中。因此,需要使用前要在项目的 build.gradle 文件中添加相应依赖库:
在这里插入图片描述

修改布局文件 listview_layout.xml 中控件 ListViewRecyclerView,并修改布局文件名称为 recyclerview_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recycler_view"android:layout_width="match_parent"android:layout_height="match_parent"/></androidx.constraintlayout.widget.ConstraintLayout>

子项布局文件 fruit_item.xml 和自定义的 Fruit 类无需修改,但适配器 FruitAdapter 类需要重新实现,原本 getView 方法的职责被三个方法替代:

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {private List<Fruit> FruitList;// 构造函数public FruitAdapter(List<Fruit> fruitList){FruitList = fruitList;}// 三个继承自父类的函数// 创建内部类实例@NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);return new ViewHolder(view);}// 将获得的Fruit实例作为RecyclerView子项控件的值@Overridepublic void onBindViewHolder(@NonNull ViewHolder holder, int position) {Fruit fruit = FruitList.get(position); // 获得子项holder.fruitImage.setImageResource(fruit.getImageId());holder.fruitName.setText(fruit.getName());}// 统计子项数目@Overridepublic int getItemCount() {return FruitList == null ? 0 : FruitList.size();}// 缓存Fruit属性对应控件的内部类static class ViewHolder extends RecyclerView.ViewHolder{ImageView fruitImage;TextView fruitName;public ViewHolder(@NonNull View itemView) {super(itemView);fruitImage = itemView.findViewById(R.id.fruit_image);fruitName = itemView.findViewById(R.id.fruit_name);}}
}

活动文件 ListViewTest.java

public class ListViewTest extends AppCompatActivity {private List<Fruit> fruitList = new ArrayList<>();@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.recyclerview_layout);initFruits();RecyclerView recyclerView = findViewById(R.id.recycler_view);// 指定RecyclerView布局方式为线性布局LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);recyclerView.setLayoutManager(linearLayoutManager);// 设置适配器recyclerView.setAdapter(new FruitAdapter(fruitList));}private void initFruits(){for(int i = 0; i < 10; i++){Fruit fruit = new Fruit("apple", R.drawable.cmy1);fruitList.add(fruit);}}
}

与 ListView 不同的是,需要传入一个布局管理器 LinearLayoutManager 来规定 RecyclerView 是何种布局,一般有三种:

  • GridLayoutManager:网格布局
  • LinearLayoutManager:线性布局
  • StaggeredGridLayoutManager:瀑布流布局

这里以瀑布流布局为例:

StaggeredGridLayoutManager layoutManager = newStaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);// 表示会把布局分为三列,并纵向排列
recyclerView.setLayoutManager(layoutManager);

运行结果:
在这里插入图片描述
这里看起来像网格布局是因为每个子项的长宽是一样的,当长宽不一样时就会呈现这样的效果:
在这里插入图片描述

此外,还可实现横向滚动:

    protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.recyclerview_layout);initFruits();RecyclerView recyclerView = findViewById(R.id.recycler_view);// 指定RecyclerView布局方式为线性布局LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);// 布局横向排列以便横向滚动linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);recyclerView.setLayoutManager(linearLayoutManager);// 设置适配器recyclerView.setAdapter(new FruitAdapter(fruitList));}

点击事件

不同于 ListView,RecyclerView 没有类似于 setOnItemClickListener 这样的注册监听器方法,这需要给子项具体的 View 注册点击事件。

修改适配器类 FruitAdapter.javaonCreateViewHolder 函数,实现点击 Fruit 子项的文字部分会弹出 Toast 文本;点击 Fruit 子项的图片部分会显示大图:

public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);final ViewHolder holder = new ViewHolder(view);holder.itemView.setOnClickListener((View v)->{Toast.makeText(v.getContext(), "clicked view", Toast.LENGTH_SHORT).show();});holder.fruitImage.setOnClickListener((View v)->{// 获取当前子项实例int position = holder.getAdapterPosition();Fruit fruit = FruitList.get(position);// 使用Dialog显示大图final Dialog dialog = new Dialog(v.getContext());// 设置缓存图片的ImageView控件ImageView img = new ImageView(v.getContext());// 用当前Fruit实例的成员(图片id)为img控件赋值img.setImageResource(fruit.getImageId());/* 也可以不使用position一连串操作,而是通过setImageDrawable将holder.fruitImage的图片显示到img中img.setImageDrawable(holder.fruitImage.getDrawable());*/// 设置dialog弹出内容dialog.setContentView(img);// 对话框背景为透明dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);// 显示dialogdialog.show();// 点击图片取消img.setOnClickListener((View vi)->{dialog.cancel();});});return holder;}

点击图片的运行结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443707.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android入门(10)| Fragment碎片详解

文章目录为什么要使用碎片&#xff08;Fragment&#xff09;实例布局文件FragmentActivity动态添加碎片布局文件FragmentActivity碎片通信Fragment布局文件Activity生命周期为什么要使用碎片&#xff08;Fragment&#xff09; 我们在手机上看新闻可能是这样的&#xff1a; Re…

Android开发(1) | Fragment 的应用——新闻应用

文章目录Item&#xff1a;标题子项布局文件Java代码标题碎片布局文件Java代码新闻内容碎片布局文件Java代码新闻内容活动布局文件Java代码首界面布局文件Java代码Item&#xff1a;标题子项 布局文件 news_item.xml&#xff1a; <TextViewxmlns:android"http://schema…

Android入门(11)| 全局广播与本地广播

文章目录广播概念接收广播动态注册实例静态注册实例发送广播发送标准广播广播的跨进程特性发送有序广播本地广播广播概念 Android 中的每个应用程序都可以对自己感兴趣的广播进行注册&#xff0c;这样该程序就只会接收到自己所关心的广播内容&#xff0c;这些广播可能是来自系…

Android开发(2) | 广播 Broadcast 的应用——强制下线功能

文章目录功能简介关闭所有活动登陆界面发送强制下线的广播广播接收器AndroidManifest.xml运行结果功能简介 强制下线功能只需要弹出一个对话框&#xff0c;让用户只能点击确定按钮&#xff0c;回到登录界面。 如果在每一个活动中添加一个对话框的话太过繁琐&#xff0c;用广播…

Android入门(12)| 数据持久化

文章目录数据持久化文件存储将数据存储进文件实例从文件中读取数据实例SharedPreferences存储将数据存储进文件实例从文件中读取数据实例实现记住密码的功能SQLite数据库存储创建自己的帮助类调用自己的帮助类补全 onUpgrade() 方法增删查改增&#xff1a;SQLiteDatabase.inser…

Android入门(13)| Android权限 与 内容提供器

文章目录普通权限与危险权限运行时申请权限内容提供器运用安卓封装好的内容提供器自实现的内容提供器概念实现普通权限与危险权限 主要用于不同应用程序之间在保证被访数据的安全性的基础上&#xff0c;实现数据共享的功能。 在 Android 6.0 开始引入了运行时权限的功能&…

Android入门(14)| 通知

文章目录创建通知点击效果其它小功能实例创建通知 创建通知的步骤&#xff1a; 管理通知的 NotificationManager&#xff0c;通常通过当前 Context 的 getSystemService() 获取实例。它接受一个字符串参数用于确定获取系统的什么服务。Android 8.0(O) 版本后需要通知通道&…

Android开发(3) | 权限和内容提供器的应用——调用相机和相册

文章目录拍照并保存到 ImageView 控件布局文件 notice_layout.xml按钮 button_takePhoto 的点击操作隐式 Intent 启动后的回调AndroidManifest.xml从相册选取照片并在 ImageView 控件中显示布局文件 notice_layout.xml按钮 button_takePhoto 的点击操作自定义打开相册的方法 op…

Android开发(4) | 系统权限、MediaPlayer类 和 VideoView类 的应用——播放多媒体文件

文章目录MediaPlayer类播放音频的实例VideoView类播放视频的实例MediaPlayer类 对多种格式的音频文件提供了全面的控制方法&#xff1a; 如何获得MediaPlayer实例&#xff1f; 通过构造函数&#xff1a; MediaPlayer mp new MediaPlayer();调用 MediaPlayer.create() 方法&…

Android入门(15)| 网络

文章目录WebViewHTTP使用HttpURLConnection使用OkHttp封装网络操作封装HttpURLConnection封装OkHttpWebView WebView 可以在 应用程序中&#xff08;而不是浏览器&#xff09; 展示一些网页。 布局文件 web_layout.xml&#xff1a; <LinearLayoutxmlns:android"http…

Android入门(16)| 服务

文章目录概念Android 多线程继承 Thread继承 Runable 接口匿名类异步消息处理AsyncTask使用服务框架启动/停止服务绑定/解绑服务服务的生命周期前台服务IntentService完整版下载示例下载过程的回调接口&#xff1a;DownloadListener继承 AsyncTask 实现下载功能&#xff1a;Dow…

2020德勤面试开始了吗_2020国考面试开始,近期面试公告汇总,附结构化小组面试流程...

2020年国家公务员考试面试环节逐步恢复考试&#xff0c;各个招录部门已经发布面试考察公告&#xff0c;对于进入面试环节的国考考生来说&#xff0c;有必要了解近期国考面试的招录动态&#xff0c;提前做好面试准备。2020国考国家统计局机关面试面试确认&#xff1a;请进入面试…

项目积压需求项目计划_需求变更频繁,项目经理如何做好需求管理?

项目实施过程中&#xff0c;项目经理常常面临一个重大挑战——需求变更。需求变更无处不在&#xff0c;市场条件变化、新业务出现、战略目标调整、客户需求修改、资源限制等&#xff0c;都会造成需求变更。需求变更会影响项目的时间、成本和质量&#xff0c;对整个项目和团队成…

Android | Sensor.TYPE_ORIENTATION被废弃后的解决办法

文章目录概述getOrientation 方法根据 旋转矩阵R 获取 设备旋转弧度getRotationMatrix 方法根据 地磁场、加速度传感器对象 获取 旋转矩阵R代码参考资料概述 Sensor.TYPE_ORIENTATION 常数在 API 8 中已弃用&#xff0c;官方推荐使用 SensorManager.getOrientation() 替代。关…

【JAVA 开发小问题】 | String操作合集

文章目录截取特定两个字符之间的字符串截取特定两个字符之间的字符串 利用正则表达式&#xff0c;图片来源

uniapp 刷新后数据都没有了_环境温度传感器都没有连接,竟然还会有数据?

福田欧曼GTL(福康发动机、康明斯2880系统)匹配ECoffit尿素泵●故障现象&#xff1a;OBD故障灯点亮&#xff0c;不烧尿素&#xff0c;油耗高&#xff0c;动力不足●故障码&#xff1a;●维修分析&#xff1a;①故障指出加热器问题&#xff0c;摸下尿素箱温度&#xff0c;发现烫手…

保姆级教学!Xcode 配置 OpenGL 环境

文章目录GLFW获取 GLFWGLAD获取 GLAD在 Xcode 中配置下载好的 GLFW 和 GLAD配置流程检测是否配置成功无关配置的题外话——Xcode 下安全的删除移动操作GLFW Graphics Library Framework&#xff08;图形库框架&#xff09;&#xff0c;可以让我们通过其封装好的 通用API 来正确…

Android入门(17)| 百度提供的 Android定位SDK

文章目录配置百度提供的 Android定位SDK用于发布的 SHA1用于测试的 SHA1使用百度定位实例配置百度提供的 Android定位SDK 详情参见官方文档&#xff0c;这里仅对获取 SHA1 做详细介绍&#xff1a; 用于发布的 SHA1 用于测试的 SHA1 使用百度定位实例 public class LocationAc…

ios 不被遮挡 阴影_为何你没见到日环食?你不知道的天象常识原来还有这么多 | 返朴...

关注风云之声提升思维层次导读说好的日环食呢&#xff0c;为什么上周很多人只等到了日偏食?日食月食的时间和种类是怎么预测的?你真的弄懂了各种日食和月食的成因吗&#xff1f;你了解它们有什么区别和联系&#xff0c;又遵循什么样的时间规律吗? 日食和月食发生的频率一样吗…

初识贝塞尔(bezier)曲线

文章目录资料援引贝塞尔曲线的用途一阶贝塞尔&#xff08;bezier&#xff09;曲线二阶贝塞尔&#xff08;bezier&#xff09;曲线三阶贝塞尔&#xff08;bezier&#xff09;曲线高阶贝塞尔&#xff08;bezier&#xff09;曲线三阶贝塞尔曲线求插值&#xff08;Slerp&#xff09…