百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

Android开发;Flutter页面-widget基础,State生命周期如何进行?

yuyutoo 2024-10-12 01:29 16 浏览 0 评论

享学课堂特邀作者: 潇湘夜雨

转载请声明出处!

Flutter页面-基础Widget

在Flutter中,几乎所有的对象都是一个 Widget,与原生开发中的控件不同的是,Flutter中的 widget的概念更广泛,它不仅可以表示UI元素,也可以表示一些功能性的组件如:用于手势检测的 GestureDetector widget、用于应用主题数据传递的 Theme等等。由于Flutter主要就是用于构建用户界面的,所以,在大多数时候,可以认为widget就是一个控件,不必纠结于概念。

Widget的功能是“描述一个UI元素的配置数据”,Widget其实并不是表示最终绘制在设备屏幕上的显示元素,而只是显示元素的一个配置数据。实际上,Flutter中真正代表屏幕上显示元素的类是 Element,也就是说Widget只是描述 Element的一个配置。一个Widget可以对应多个 Element,这是因为同一个Widget对象可以被添加到UI树的不同部分,而真正渲染时,UI树的每一个节点都会对应一个 Element对象。

Widget

StatelessWidget和 StatefulWidget是 flutter的基础组件,日常开发中自定义 Widget都是选择继承这两者之一。也是在往后的开放中,我们最多接触的Widget:
StatelessWidget:无状态的,展示信息,面向那些始终不变的UI控件;
StatefulWidget:有状态的,可以通过改变状态使得 UI 发生变化,可以包含用户交互(比如弹出一个 dialog)。

在实际使用中,Stateless与Stateful的选择需要取决于这个 Widget 是有状态还是无状态,简单来说看界面是否需要更新。

StatelessWidget

StatelessWidget用于不需要维护状态的场景,它通常在 build方法中通过嵌套其它Widget来构建UI,在构建过程中会递归的构建其嵌套的Widget。

BuildContext表示构建widget的上下文,它是操作widget在树中位置的一个句柄,它包含了一些查找、遍历当前Widget树的一些方法。每一个widget都有一个自己的context对象。

import 'package:flutter/material.dart';
void main ()=> runApp (StatelessApp());
class StatelessApp extends StatelessWidget {
 //在build方法中通过嵌套其它Widget来构建UI,在构建过程中会递归的构建其嵌套的Widget
 @override
 Widget build(BuildContext context) {
 //嵌套 MaterialApp:封装了应用程序实现Material Design所需要的一些widget
 return MaterialApp(
 title: "Widget演示",
 //标题,显示在recent时候的标题
 //主页面
 //Scaffold : Material Design布局结构的基本实现。
 home: Scaffold(
 //ToolBar/ActionBar
 appBar:AppBar(title: Text("Widget")), 
 body: Text("Hello,Flutter!"),
 )
 );
 }
}

Material Design:

一种设计语言,Material Design 于2014年的 Google I/O
首次亮相,是谷歌推出的全新的设计语言。说白了,就是一种设计风格。

StatefulWidget

StatefulWidget是动态的,添加了一个新的接口 createState()用于创建和Stateful widget相关的状态 State,它在Stateful widget的生命周期中可能会被多次调用。

当State被改变时,可以手动调用其 setState()方法通知Flutter framework状态发生改变,Flutter framework在收到消息后,会重新调用其 build方法重新构建widget树,从而达到更新UI的目的。

class StatefulState extends State<StatefulApp>
 {
 int _i;
///当Widget第一次插入到Widget树时会被调用,对于每一个State对象,Flutter framework只会调用一次该回调
@override
 void initState() { 
 super.initState();
 _i= 1; 
 }
@override
 Widget build (BuildContext context) {
 return MaterialApp (
 title: "Widget演示",
 theme: ThemeData(),
 home:Scaffold (
 appBar: AppBar (title: Text("Widget")),
 body: RaisedButton (
 onPressed: () { 
//修改状态,setState会重新调用build更新ui
 setState(() {_i++;});
 },
 child: Text("Hello,Flutter! $_i"),
 ),
 ));
 }
}

State生命周期

State的生命周期为:


State类除了 build之外还提供了很多方法能够让我们重写,这些方法会在不同的状态下由Flutter调起执行,所以这些方法我们就称之为生命周期方法。在这里我们用statefulwidget点击按钮后移除子statefulwidget。

import 'package:flutter/material.dart';
void main () => runApp(MyApp());
class MyApp extends StatefulWidget {
 @override
 _MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
 bool isShowChild; 
///当Widget第一次插入到Widget树时会被调用,对于每一个State对象,Flutter framework只会调用一次该回调
 @override
 void initState() {
 super.initState();
 isShowChild = true;
 debugPrint("parent initState......"); 
} 
///初始化时,在initState()之后立刻调用 
///当依赖的InheritedWidget rebuild,会触发此接口被调用
 
@override
 void didChangeDependencies() { 
 super.didChangeDependencies();
 debugPrint("parent didChangeDependencies......"); 
}
///绘制界面,当setState触发的时候会再次被调用
 
@override
 Widget build(BuildContext context) {
 debugPrint("parent build......"); 
 return MaterialApp(
 home: Scaffold( 
 body: Center(
 child: RaisedButton(
 onPressed: () {
 setState(() {
 isShowChild = !isShowChild; 
 }); 
 },
 child: isShowChild ? Child() : Text("演示移除Child"), 
 )), 
 ),
 ); 
 }

 ///状态改变的时候会调用该方法,比如调用了setState
 
@override
 void didUpdateWidget(MyApp oldWidget) {
 super.didUpdateWidget(oldWidget);
 debugPrint("parent didUpdateWidget......"); 
} 
///当State对象从树中被移除时,会调用此回调
 
@override 
void deactivate() {
 super.deactivate();
 debugPrint('parent deactivate......'); 
}
 
///当State对象从树中被永久移除时调用;通常在此回调中释放资源
 
@override 
void dispose() { 
 super.dispose();
 debugPrint('parent dispose......'); 
 }
}
class Child extends StatefulWidget {
 
 @override
 _ChildState createState() => _ChildState();}
class _ChildState extends State<Child> {
 
@override 
 Widget build(BuildContext context) {
 debugPrint("child build......"); 
 return Text('lifeCycle'); 
 }
 
@override
 void initState() { 
 super.initState();
 debugPrint("child initState......"); 
} 
///初始化时,在initState()之后立刻调用 
///当依赖的InheritedWidget rebuild,会触发此接口被调用
 
@override 
void didChangeDependencies() { 
 super.didChangeDependencies();
 debugPrint("child didChangeDependencies......"); 
}
 ///父widget状态改变的时候会调用该方法,比如父节点调用了setState
 
@override
 void didUpdateWidget(Child oldWidget) {
 super.didUpdateWidget(oldWidget);
 debugPrint("child didUpdateWidget......"); 
} 
///当State对象从树中被移除时,会调用此回调
 
@override
 void deactivate() { 
 super.deactivate();
 debugPrint('child deactivate......'); 
} 
///当State对象从树中被永久移除时调用;通常在此回调中释放资源
 
@override
 void dispose() { 
 super.dispose();
 debugPrint('child dispose......'); 
 }
}

执行的输出结果显示为:

  • 运行到显示
I/flutter (22218): parent initState......
I/flutter (22218): parent didChangeDependencies......
I/flutter (22218): parent build......
I/flutter (22218): child initState......
I/flutter (22218): child didChangeDependencies......
I/flutter (22218): child build......
  • 点击按钮会移除Child
I/flutter (22218): parent build......
I/flutter (22218): child deactivate......
I/flutter (22218): child dispose......
  • 将MyApp的代码由 child:isShowChild?Child():Text(“演示移除Child”),改为
    child:Child(),点击按钮时
I/flutter (22765): parent build......
I/flutter (22765): child didUpdateWidget......
I/flutter (22765): child build......

基础widget

文本显示

Text

Text是展示单一格式的文本Widget(Android TextView)。

import 'package:flutter/material.dart';
/// main方法 调用runApp传递Widget,这个Widget成为widget树的根
void main() => runApp(TextApp());
/// 1、单一文本Text
//创建一个无状态的Widget
class TextApp extends
 StatelessWidget { 
 
@override
 Widget build(BuildContext context) { 
//封装了应用程序实现Material Design所需要的一些widget
 return MaterialApp(
 title: "Text演示",
//标题,显示在recent时候的标题 
//主页面 
//Scaffold : Material Design布局结构的基本实现。
 home: Scaffold( 
//ToolBar/ActionBar
 appBar: AppBar(title: Text("Text")),
 body: Text("Hello,Flutter"
 ), 
 ), 
 ); 
 }
}

在使用 Text显示文字时候,可能需要对文字设置各种不同的样式,类似Android的 android:textColor/Size等

在Flutter中也拥有类似的属性

Widget _TextBody() { 
 return Text(
 "Hello,Flutter",
 style: TextStyle( 
 //颜色
 color: Colors.red, 
//字号 默认14
 fontSize: 18, 
//粗细
 fontWeight: FontWeight.w800, 
//斜体
 fontStyle: FontStyle.italic, 
//underline:下划线,overline:上划线,lineThrough:删除线
 decoration: TextDecoration.lineThrough,
 decorationColor: Colors.black, 
//solid:实线,double:双线,dotted:点虚线,dashed:横虚线,wavy:波浪线
 decorationStyle: 
 TextDecorationStyle.wavy), 
 );
}
class TextApp extends StatelessWidget {
 
@override 
 Widget
 build(BuildContext context) 
 { 
 return MaterialApp(
 title: "Text演示", 
 home: Scaffold(
 appBar: AppBar(title: Text("Text")),
 body: _TextBody(), 
 ), 
 ); 
 }
}


RichText

如果需要显示更为丰富样式的文本(比如一段文本中文字不同颜色),可以使用 RichText或者 Text.rich

Widget _RichTextBody() { 
 var textSpan = TextSpan(
 text: "Hello",
 style: TextStyle(color: Colors.red),
 children: [
 TextSpan(text: "Flu", style: TextStyle(color: Colors.blue)),
 TextSpan(text: "uter", style: TextStyle(color: Colors.yellow)),
 ], 
);
 //Text.rich(textSpan);
 return RichText(text: textSpan);
}


DefaultTextStyle
在widget树中,文本的样式默认是可以被继承的,因此,如果在widget树的某一个节点处设置一个默认的文本样式,那么该节点的子树中所有文本都会默认使用这个样式。相当于在Android中定义 Theme

Widget _DefaultStyle(){
 DefaultTextStyle( 
//设置文本默认样式
 style: TextStyle(
 color:Colors.red,
 fontSize: 20.0, 
),
 textAlign: TextAlign.start,
 child: Column(
 crossAxisAlignment: 
 CrossAxisAlignment.start,
 children: <Widget>[ 
 Text("Hello Flutter!"), 
 Text("Hello Flutter!"), 
 Text("Hello Flutter!",
 style: TextStyle(
 inherit: false, 
//不继承默认样式
 color: Colors.grey
 ), 
 ), 
 ], 
 ), 
 );
}

FlutterLogo
这个Widget用于显示Flutter的logo…

Widget flutterLogo() { 
 return FlutterLogo( 
//大小
 size: 100, 
//logo颜色 默认为 Colors.blue
 colors: Colors.red,
//markOnly:只显示logo,horizontal:logo右边显示flutter文字,stacked:logo下面显示文字
 style: FlutterLogoStyle.stacked, 
//logo上文字颜色
 textColor: Colors.blue, 
 );
}


Icon

主要用于显示内置图标的 Widget

Widget icon() { 
 return Icon( 
//使用预定义Material icons 
// https://docs.flutter.io/flutter/material/Icons-class.html
 
Icons.add,
 size: 100,
 color: Colors.red);
}


Image
显示图片的 Widget。图片常用的格式主要有bmp,jpg,png,gif,webp等,Android中并不是天生支持gif和webp动图,但是这一特性在flutter中被很好的支持了。


Iamge.asset
在工程目录下创建目录,如:assets,将图片放入此目录。打开项目根目录:pubspec.yaml

return MaterialApp(
 title: "Image演示",
 home: Scaffold(
 appBar: AppBar(title: Text("Image")),
 body: Image.asset("assets/banner.jpeg"), 
 ),
);

Image.file
在sd卡中放入一张图片。然后利用path_provider库获取sd卡根目录(Dart库版本可以在:https://pub.dartlang.org/packages查询)。


注意权限

class ImageState extends State<ImageApp> { 
 Image image; 
 
@override
 void initState() { 
 super.initState();
 getExternalStorageDirectory().then((path) {
 setState(() {
 image = Image.file(File("${path.path}${Platform.pathSeparator}banner.jpeg"
 ));
 });
 }); 
}
 
@override 
Widget build(BuildContext context) { 
return MaterialApp(
 title: "Image演示",
 home: Scaffold(
 appBar: AppBar(title: Text("Image")),
 body: image, 
 ), 
 ); 
 }
}

Image.network

直接给网络地址即可。
Flutter 1.0,加载https时候经常出现证书错误。必须断开AS打开app

Image.memory

Future<List<int>> _imageByte() async { 
 String path = (await getExternalStorageDirectory()).path; 
 return await File("$path${Platform.pathSeparator}banner.jpeg").readAsBytes();
}
class ImageState extends State<ImageApp> { 
 Image image;
 
@override
 void initState() { 
 super.initState();
 _imageByte().then((bytes) { 
 setState(() {
 image = Image.memory(bytes);
 });
 }); 
}
 
@override 
Widget build(BuildContext context) { 
 return MaterialApp(
 title: "Image演示",
 home: Scaffold(
 appBar: AppBar(title: Text("Image")),
 body: image, 
 ),
 );
 }
}

CircleAvatar

CircleAvatar( 
 //图片提供者 ImageProvider
 backgroundImage: AssetImage("assets/banner.jpeg"), 
 //半径,控制大小
 radius: 50.0, 
 );

FadeInImage
当使用默认 Image widget显示图片时,您可能会注意到它们在加载完成后会直接显示到屏幕上。这可能会让用户产生视觉突兀。如果最初显示一个占位符,然后在图像加载完显示时淡入,我们可以使用 FadeInImage来达到这个目的!

 image = FadeInImage.memoryNetwork(
 placeholder: kTransparentImage,
 image: 'https://flutter.io/images/homepage/header-illustration.png', 
);

按钮

Material widget库中提供了多种按钮Widget如RaisedButton、FlatButton、OutlineButton等,它们都是直接或间接对RawMaterialButton的包装定制,所以他们大多数属性都和 RawMaterialButton一样。所有Material 库中的按钮都有如下相同点:

  1. 按下时都会有“水波动画”。
  2. 有一个onPressed属性来设置点击回调,当按钮按下时会执行该回调,如果不提供该回调则按钮会处于禁用状态,禁用状态不响应用户点击。

RaisedButton
"漂浮"按钮,它默认带有阴影和灰色背景

RaisedButton(
 child: Text("normal"),
 onPressed: () => {}, 
)

FlatButton

扁平按钮,默认背景透明并不带阴影

FlatButton(
 child: Text("normal"),
 onPressed: () => {}, 
)

OutlineButton

默认有一个边框,不带阴影且背景透明。

OutlineButton(
 child: Text("normal"),
 onPressed: () => {}, 
)

IconButton

可点击的Icon

IconButton(
 child: Text("normal"),
 onPressed: () => {}, 
)

按钮外观可以通过其属性来定义,不同按钮属性大同小异

const FlatButton({
 ... 
@required this.onPressed, //按钮点击回调 
this.textColor, //按钮文字颜色 
this.disabledTextColor, //按钮禁用时的文字颜色 
this.color, //按钮背景颜色
this.disabledColor,//按钮禁用时的背景颜色
this.highlightColor, //按钮按下时的背景颜色 
this.splashColor, //点击时,水波动画中水波的颜色
this.colorBrightness,//按钮主题,默认是浅色主题 
this.padding, //按钮的填充 
this.shape, //外形 
@required this.child, //按钮的内容
})
 FlatButton( onPressed: () => {}, 
 child: Text("Raised"), 
//蓝色
 color: Colors.blue, 
//水波
 splashColor: Colors.yellow, 
//深色主题,这样文字颜色会变成白色
 colorBrightness: Brightness.dark, 
//圆角按钮
 shape: RoundedRectangleBorder(
 borderRadius: BorderRadius.circular(50) 
 ),
)

而 RaisedButton,默认配置有阴影,因此在配置 RaisedButton 时,拥有一系列 elevation 属性的配置

const RaisedButton({ 
 ... 
 this.elevation = 2.0, 
//正常状态下的阴影 
 this.highlightElevation = 8.0,
//按下时的阴影
 this.disabledElevation = 0.0,
// 禁用时的阴影
 ...
}

输入框

import 'package:flutter/material.dart';
 void main() => runApp(Demo1());
 class Demo1 extends StatelessWidget {
 
@override
 Widget build(BuildContext context) {
 return MaterialApp(
 title: "Demo1",
 home: Scaffold(
 appBar: AppBar(
 title: Text("登录"), 
 ),
 //线性布局,垂直方向
 body: Column(
 children: <Widget>[ 
 TextField( 
//自动获得焦点
 autofocus: true,
 decoration: InputDecoration(
 labelText: "用户名",
 hintText: "用户名或邮箱",
 prefixIcon: Icon(Icons.person)),
 ),
 TextField( 
//隐藏正在编辑的文本
 obscureText: true,
 decoration: InputDecoration(
 labelText: "密码",
 hintText: "您的登录密码",
 prefixIcon: Icon(Icons.lock)),
 ),
 ],
 ), 
 ),
 ); 
 }
}


这个效果非常的“系统”,我们可能大多数情况下需要将下划线更换为矩形边框,这时候可能就需要组合widget来完成:

//容器 设置一个控件的尺寸、背景、margin 
Container(
 margin: EdgeInsets.all(32),
 child: TextField(
 keyboardType: TextInputType.emailAddress,
 decoration: InputDecoration(
 labelText: "用户名",
 hintText: "用户名或邮箱",
 prefixIcon: Icon(Icons.person),
 border: InputBorder.none 
//隐藏下划线
)),
//装饰
 decoration: BoxDecoration( 
// 边框浅灰色,宽度1像素
 border: Border.all(color: Colors.red[200], width: 1.0), 
//圆角
 borderRadius: BorderRadius.circular(5.0),
 ),
 )

焦点控制

FocusNode: 与Widget绑定,代表了这个Widget的焦点

FocusScope: 焦点控制范围

FocusScopeNode:控制焦点

class _TextFocusState extends State<TextFocusWidget> {
 FocusNode focusNode1 = new 
 FocusNode(); FocusNode focusNode2 = new FocusNode(); 
void _listener() {
 debugPrint("用户名输入框焦点:${focusNode1.hasFocus}"); 
}
 
@override
 void initState() { 
 super.initState(); 
//监听焦点状态改变事件
 focusNode1.addListener(_listener); 
}
 
@override
 void dispose() {
 super.dispose();
 focusNode1.dispose();
 focusNode2.dispose(); 
}
 
@override
 Widget build(BuildContext context) {
 return Column(
 children: <Widget>[
 TextField(
 autofocus: true, 
//关联焦点
 focusNode: focusNode1, 
//设置键盘动作为: 下一步
 textInputAction: TextInputAction.next, 
//点击下一步执行回调
 onEditingComplete: () { 
//获得 context对应UI树的焦点范围 的焦点控制器
 FocusScopeNode focusScopeNode = FocusScope.of(context); 
//将焦点交给focusNode2
 focusScopeNode.requestFocus(focusNode2);
 },
 decoration: InputDecoration(
 labelText: "用户名",
 hintText: "用户名或邮箱",
 prefixIcon: Icon(Icons.person)),
 ),
 TextField( 
//隐藏正在编辑的文本
 obscureText: true,
 focusNode: focusNode2,
 decoration: InputDecoration(
 labelText: "密码",
 hintText: "您的登录密码",
 refixIcon: Icon(Icons.lock)),
 ),
 custom(),
 ],
 );
 }
}

获取输入内容

获取输入内容有两种方式:

  1. 定义两个变量,用于保存用户名和密码,然后在onChange触发时,各自保存一下输入内容。
  2. 通过controller直接获取。
    onChange获得输入内容:
TextField(
 onChanged: (s) => debugPrint("ssss:$s"),

controller获取:

定义一个controller:

//定义一个controller
TextEditingController _unameController=new TextEditingController();

然后设置输入框controller:

TextField(
 controller: _unameController, 
//设置controller
 ...
)

通过controller获取输入框内容

debugPrint(_unameController.text)

TextFormField

TextFormField比 TextField多了一些属性,其中 validator用于设置验证回调。在单独使用时与 TextField没有太大的区别。当结合 From,利用 From可以对输入框进行分组,然后进行一些统一操作(验证)

class _TextFocusState extends State<TextFocusWidget> { 
 //全局key
 GlobalKey<FormState> _key = GlobalKey<FormState>(); 
 
@override 
 Widget build(BuildContext context) {
 return Form( 
//类似 id
 key: _key, 
 child: Column(
 children: <Widget>[ 
 TextFormField(
 autofocus: true,
 decoration: InputDecoration(
 labelText: "用户名",
 hintText: "用户名或邮箱",
 icon: Icon(Icons.person)), 
// 校验用户名
 validator: (v) {
 return v.trim().length > 0 ? null : "用户名不能为空";
 }),
 TextFormField(
 decoration: InputDecoration(
 labelText: "密码", 
 hintText: "您的登录密码",
 icon: Icon(Icons.lock)), 
// 校验用户名
 validator: (v) {
 return v.trim().length > 0 ? null : "密码不能为空";
 }),
 RaisedButton(
 onPressed: () { 
//Form所有TextFormField成功 返回true
 if (_key.currentState.validate()) {
 }
 },
 child: Text("提交"),
 )
 ], 
 )); 
 }
}

喜欢本文的话可以关注我们的官方账号,第一时间获取资讯。

你的关注是对我们更新最大的动力哦~

相关推荐

Mysql和Oracle实现序列自增(oracle创建序列的sql)

Mysql和Oracle实现序列自增/*ORACLE设置自增序列oracle本身不支持如mysql的AUTO_INCREMENT自增方式,我们可以用序列加触发器的形式实现,假如有一个表T_WORKM...

关于Oracle数据库12c 新特性总结(oracle数据库19c与12c)

概述今天主要简单介绍一下Oracle12c的一些新特性,仅供参考。参考:http://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT...

MySQL CREATE TABLE 简单设计模板交流

推荐用MySQL8.0(2018/4/19发布,开发者说同比5.7快2倍)或同类型以上版本....

mysql学习9:创建数据库(mysql5.5创建数据库)

前言:我也是在学习过程中,不对的地方请谅解showdatabases;#查看数据库表createdatabasename...

MySQL面试题-CREATE TABLE AS 与CREATE TABLE LIKE的区别

执行"CREATETABLE新表ASSELECT*FROM原表;"后,新表与原表的字段一致,但主键、索引不会复制到新表,会把原表的表记录复制到新表。...

Nike Dunk High Volt 和 Bright Spruce 预计将于 12 月推出

在街上看到的PandaDunk的超载可能让一些球鞋迷们望而却步,但Dunk的浪潮仍然强劲,看不到尽头。我们看到的很多版本都是为女性和儿童制作的,这种新配色为后者引入了一种令人耳目一新的新选择,而...

美国多功能舰载雷达及美国海军舰载多功能雷达系统技术介绍

多功能雷达AN/SPY-1的特性和技术能力,该雷达已经在美国海军服役了30多年,其修改-AN/SPY-1A、AN/SPY-1B(V)、AN/SPY-1D、AN/SPY-1D(V),以及雷神...

汽车音响怎么玩,安装技术知识(汽车音响怎么玩,安装技术知识视频)

全面分析汽车音响使用或安装技术常识一:主机是大多数人最熟习的音响器材,有关主机的各种性能及规格,也是耳熟能详的事,以下是一些在使用或安装时,比较需要注意的事项:LOUDNESS:几年前的主机,此按...

【推荐】ProAc Response系列扬声器逐个看

有考牌(公认好声音)扬声器之称ProAcTablette小音箱,相信不少音响发烧友都曾经,或者现在依然持有,正当大家逐渐掌握Tablette的摆位设定与器材配搭之后,下一步就会考虑升级至表现更全...

#本站首晒# 漂洋过海来看你 — BLACK&amp;DECKER 百得 BDH2000L无绳吸尘器 开箱

作者:初吻给了烟sco混迹张大妈时日不短了,手没少剁。家里有了汪星人,吸尘器使用频率相当高,偶尔零星打扫用卧式的实在麻烦(汪星人:你这分明是找借口,我掉毛是满屋子都有,铲屎君都是用卧式满屋子吸的,你...

专题|一个品牌一件产品(英国篇)之Quested(罗杰之声)

Quested(罗杰之声)代表产品:Q212FS品牌介绍Quested(罗杰之声)是录音监听领域的传奇品牌,由英国录音师RogerQuested于1985年创立。在成立Quested之前,Roger...

常用半导体中英对照表(建议收藏)(半导体英文术语)

作为一个源自国外的技术,半导体产业涉及许多英文术语。加之从业者很多都有海外经历或习惯于用英文表达相关技术和工艺节点,这就导致许多英文术语翻译成中文后,仍有不少人照应不上或不知如何翻译。为此,我们整理了...

Fyne Audio F502SP 2.5音路低音反射式落地音箱评测

FyneAudio的F500系列,有新成员了!不过,新成员不是新的款式,却是根据原有款式提出特别版。特别版产品在原有型号后标注了SP字样,意思是SpecialProduction。Fyne一共推出...

有哪些免费的内存数据库(In-Memory Database)

以下是一些常见的免费的内存数据库:1.Redis:Redis是一个开源的内存数据库,它支持多种数据结构,如字符串、哈希表、列表、集合和有序集合。Redis提供了快速的读写操作,并且支持持久化数据到磁...

RazorSQL Mac版(SQL数据库查询工具)

RazorSQLMac特别版是一款看似简单实则功能非常出色的SQL数据库查询、编辑、浏览和管理工具。RazorSQLformac特别版可以帮你管理多个数据库,支持主流的30多种数据库,包括Ca...

取消回复欢迎 发表评论: