我的编程空间,编程开发者的网络收藏夹
学习永远不晚

FlutterTVAndroid端开发技巧详细教程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

FlutterTVAndroid端开发技巧详细教程

前言

最近公司有了新的业务,把现有Flutter Android项目应用到TV上去,这不,Asscre的活就来了。

本文详细说明Flutter for TV的两种实现方式,能力有限,不足之处欢迎指点,哈哈哈

开发思路

在开发之前,我们先设定一下我们的思路。

即,如何对原有程序代码侵入式最小、性能最佳、可玩性更高做出设定。

那么,通过上面的设定,我们在Flutter Widget中就发现了两个东西:

  • RawKeyboardListener
  • InkWell和其他Android TV配置

先上效果

可玩性、可塑性更高的RawKeyboardListener解决方案效果

对原有程序修改最小的InkWell和其他Android TV配置解决方案效果

开发细节

可玩性、可塑性更高的RawKeyboardListener解决方案

使用RawKeyboardListener

RawKeyboardListener(
  focusNode: d.focusNode, // 配置focusNode
  onKey: (RawKeyEvent event) =>
      context.read<HomePageContentWidgetProvider>().focusEventHandler(event, context, d), // 对特殊事件进行监听和处理
  child: Container(
    height: 190,
    width: 190,
    decoration: BoxDecoration(
      border: Border.all(
          width: 2,
          color: d.focusNode.hasFocus ? Colors.blue : Colors.transparent),
      borderRadius: BorderRadius.circular(20),
      color: Colors.white.withAlpha(20),
    ),
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Image.asset(
          d.img,
          height: 80,
        ),
        SizedBox(height: 20),
        Text(
          d.name,
          style: TextStyle(
            color: Colors.white,
            fontSize: 32,
          ),
        ),
      ],
    ),
  ),
),

Provider层对事件进行处理

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:tv_test/pages/memory_page/memory_page.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class HomePageContentWidgetProvider
    with ChangeNotifier {
  bool init = false;
  double maxWScreen = 0; // 按钮距离屏幕右侧最大边界
  double minWScreen = 60.w; // 按钮距离屏幕最左侧距离边界
  final List<HomePageMakeBtn> makeBtnList = [
    HomePageMakeBtn('lib/assets/img/youtube.png', 'You Tube', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/apple.png', 'Apple', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/facebook.png', 'Facebook', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/douyin.png', 'Tik Tok', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/mi.png', 'MI', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/huawei.png', 'Hua Wei', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/youtube.png', 'TTT', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/apple.png', 'DDDD', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/facebook.png', 'FFFF', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/douyin.png', 'AAAA', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/mi.png', 'QQQQQ', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/huawei.png', 'WWWW', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/youtube.png', 'EEEEE', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/apple.png', 'RRRRR', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/facebook.png', 'YYYYYY', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/douyin.png', 'UUUUUU', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/mi.png', 'SSSSS', '', FocusNode()),
    HomePageMakeBtn('lib/assets/img/huawei.png', 'VVVV', '', FocusNode()),
  ];
  HomePageContentWidgetProvider(BuildContext context) {
    maxWScreen = MediaQuery.of(context).size.width - 246.w;
    // setMakeFocusAddListener();
    if (!init) {
      makeBtnList.first.focusNode.requestFocus();
      init = true;
    }
  }
  setMakeFocusAddListener() {
    for (int i = 0; i < makeBtnList.length; i++) {
      makeBtnList[i].focusNode.addListener(() {
        if (makeBtnList[i].focusNode.hasFocus) {
          // notifyListeners();
          print(
              '====${makeBtnList[i].name} : ${makeBtnList[i].focusNode.hasFocus}');
        }
      });
    }
  }
  setMakeFocusDispose() {
    for (var item in makeBtnList) {
      item.focusNode.removeListener(() {});
      item.focusNode.dispose();
    }
  }
  focusEventHandler(
      RawKeyEvent event, BuildContext context, HomePageMakeBtn param) async {
    /// 只处理按键按下的事件
    if (event.data is RawKeyEventDataAndroid &&
        event.runtimeType.toString() == 'RawKeyDownEvent') {
      CustomRawKeyEventDataAndroid _d =
          CustomRawKeyEventDataAndroid.format(event.data);
      /// 对按下确定键和中心键进行处理
      if (_d.keyCode == 23 || _d.keyCode == 66) {
        Navigator.of(context).push(
            MaterialPageRoute(builder: (_) => MemoryPage(title: param.name)));
      } else {
        // for (var e in makeBtnList) {
        //   print('${e.name} : ${e.focusNode.hasFocus}');
        // }
        /// 对左键进行处理
        if (_d.keyCode == 21) {
          await keyCodeDpadLeft(context, param);
        }
        /// 对右键进行处理
        if (_d.keyCode == 22) {
          await keyCodeDpadRight(context, param);
        }
        notifyListeners();
      }
    }
  }
  /// 对左键进行处理
  keyCodeDpadLeft(BuildContext context, HomePageMakeBtn param) async {
    /// 首位边界处理
    final int _idx = makeBtnList.indexWhere((e) => e == param);
    if (_idx == 0) return;
    final int _nextIndex = _idx + 1;
    if ((_nextIndex % 7) == 1) {
      HomePageMakeBtn _nextNode = makeBtnList[_idx - 1];
      print(_nextNode.name);
      await Future.delayed(const Duration(milliseconds: 20));
      _nextNode.focusNode.requestFocus();
    }
  }
  /// 对右键进行处理
  keyCodeDpadRight(BuildContext context, HomePageMakeBtn param) async {
    final int _idx = makeBtnList.indexWhere((e) => e == param);
    /// 末位边界处理
    if (_idx == (makeBtnList.length - 1)) return;
    final int _nextIndex = _idx + 1;
    if ((_nextIndex % 7) == 0) {
      HomePageMakeBtn _nextNode = makeBtnList[_nextIndex];
      await Future.delayed(const Duration(milliseconds: 20));
      _nextNode.focusNode.requestFocus();
    }
  }
  @override
  void dispose() {
    setMakeFocusDispose();
    super.dispose();
  }
}
class HomePageMakeBtn {
  final String img;
  final String name;
  final String routerName;
  final FocusNode focusNode;
  HomePageMakeBtn(this.img, this.name, this.routerName, this.focusNode);
}
class CustomRawKeyEventDataAndroid {
  final int flags;
  final int codePoint;
  final int plainCodePoint;
  /// case 19: KEY_UP
  /// case 20: KEY_DOWN
  /// case 21: KEY_LEFT
  /// case 22: KEY_RIGHT
  /// case 23: KEY_CENTER
  final int keyCode;
  final int scanCode;
  final int metaState;
  CustomRawKeyEventDataAndroid(this.flags, this.codePoint, this.plainCodePoint,
      this.keyCode, this.scanCode, this.metaState);
  static CustomRawKeyEventDataAndroid format(d) {
    return CustomRawKeyEventDataAndroid(d.flags, d.codePoint, d.plainCodePoint,
        d.keyCode, d.scanCode, d.metaState);
  }
}

注意

我们可以看到在处理左键和右键的时候我们用了

这是为什么呢?

那是因为在实际效果中,我们requestFocus操作的时候,Flutter的机制会首先触发一次requestFocus,然后再触发一次requestFocus,一共两次,这就与我们的预想就有冲突了。

例如:

使用按键末尾向右时,系统触发的focus到UUUUU这个按钮,我们的实际预想的是到YYYYY即可。

使用按键首位向左时,同样会跨两个focus。

目前Asscre并没有找到很好的解决方案,但使用await Future delayed可以舒缓一下这不人性的操作。

对原有程序修改最小的InkWell和其他Android TV配置解决方案

首先,我们需要在AndroidManifest.xml 设置LEANBACK_LAUNCHER告诉平台我们的程序是一个电视应用程序

<intent-filter>
    <action android:name="android.intent.action.MAIN"/>
    <category android:name="android.intent.category.LEANBACK_LAUNCHER"/> // 新增这一句
    <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>

然后,我们在Main入口文件中添加 Shortcuts用于我们的程序响应我们的遥控器指令。

return Shortcuts(
  shortcuts: <LogicalKeySet, Intent>{
    LogicalKeySet(LogicalKeyboardKey.select): ActivateIntent(),
  },
  child: MaterialApp(
  ...
);

最后,使用InkWell来获取焦点设置用户遥控点击的效果,其中focusColor帮助我们提醒用户此时的按钮位置。

    return Material(
      color: Colors.white.withAlpha(20),
      child: InkWell(
        focusColor: Colors.deepOrange.withAlpha(80),
        onTap: () => Navigator.of(context)
            .push(MaterialPageRoute(builder: (_) => MemoryPage(title: d.name))),
        child: SizedBox(
          height: 190,
          width: 190,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Image.asset(
                d.img,
                height: 80,
              ),
              SizedBox(height: 20),
              Text(
                d.name,
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 32,
                ),
              ),
            ],
          ),
        ),
      ),
    );

总结

上述两种解决方案中,大家可以根据自己(boss)的喜好或者业务需求选择一种使用。

在需要复杂的自定义的业务情况下,推荐使用RawKeyboardListener的解决方案,可以做出很多酷炫的效果,譬如按键事件触发时,focus住的widget可以做出放大、渐变等等效果,这有助于提升用户的体验。

但,要是在现有的业务逻辑上,在少量调整后就可使用上述中的InkWell的解决方案。

文件参考

TV keyCode详解

namekeycode说明
KEYCODE_UNKNOWN0
----------------------------------------------------------
KEYCODE_SOFT_LEFT1
KEYCODE_SOFT_RIGHT2
KEYCODE_HOME3HOME键
KEYCODE_BACK4返回键
KEYCODE_CALL5拨号键
KEYCODE_ENDCALL6挂机键
KEYCODE_07
KEYCODE_18
KEYCODE_29
KEYCODE_310
KEYCODE_411
KEYCODE_512
KEYCODE_613
KEYCODE_714
KEYCODE_815
KEYCODE_916
KEYCODE_STAR17按键 *
KEYCODE_POUND18按键 #
KEYCODE_DPAD_UP19向上
KEYCODE_DPAD_DOWN20向下
KEYCODE_DPAD_LEFT21向左
KEYCODE_DPAD_RIGHT22向右
KEYCODE_DPAD_CENTER23确定键
KEYCODE_VOLUME_UP24音量增加键
KEYCODE_VOLUME_DOWN25音量减小键
KEYCODE_POWER26电源键
KEYCODE_CAMERA27拍照键
KEYCODE_CLEAR28
KEYCODE_A29
KEYCODE_B30
KEYCODE_C31
KEYCODE_D32
KEYCODE_E33
KEYCODE_F34
KEYCODE_G35
KEYCODE_H36
KEYCODE_I37
KEYCODE_J38
KEYCODE_K39
KEYCODE_L40
KEYCODE_M41
KEYCODE_N42
KEYCODE_O43
KEYCODE_P44
KEYCODE_Q45
KEYCODE_R46
KEYCODE_S47
KEYCODE_T48
KEYCODE_U49
KEYCODE_V50
KEYCODE_W51
KEYCODE_X52
KEYCODE_Y53
KEYCODE_Z54
KEYCODE_COMMA55按键 ,
KEYCODE_PERIOD56按键 .
KEYCODE_ALT_LEFT57
KEYCODE_ALT_RIGHT58
KEYCODE_SHIFT_LEFT59
KEYCODE_SHIFT_RIGHT60
KEYCODE_TAB61Tab键
KEYCODE_SPACE62空格键
KEYCODE_SYM63
KEYCODE_EXPLORER64
KEYCODE_ENVELOPE65
KEYCODE_ENTER66回车键
KEYCODE_DEL67退格键
KEYCODE_GRAVE68按键 `
KEYCODE_MINUS69按键-
KEYCODE_EQUALS70按键 =
KEYCODE_LEFT_BRACKET71按键 [
KEYCODE_RIGHT_BRACKET72按键 ]
KEYCODE_BACKSLASH73按键 \
KEYCODE_SEMICOLON74按键 ,
KEYCODE_APOSTROPHE75按键 ''单引号
KEYCODE_SLASH76按键 /
KEYCODE_AT77按键 @
KEYCODE_NUM78
KEYCODE_HEADSETHOOK79
KEYCODE_FOCUS80拍照对焦键
KEYCODE_PLUS81按键+
KEYCODE_MENU82菜单键
KEYCODE_NOTIFICATION83通知键
KEYCODE_SEARCH84
KEYCODE_MEDIA_PLAY_PAUSE85多媒体键 播放/暂停
KEYCODE_MEDIA_STOP86多媒体键 暂停
KEYCODE_MEDIA_NEXT87多媒体键 下一首
KEYCODE_MEDIA_PREVIOUS88多媒体键 上一首
KEYCODE_MEDIA_REWIND89多媒体键 快退
KEYCODE_MEDIA_FAST_FORWARD90多媒体键 快进
KEYCODE_MUTE91话筒静音键
KEYCODE_PAGE_UP92向上翻页键
KEYCODE_PAGE_DOWN93向下翻页键
KEYCODE_PICTSYMBOLS94
KEYCODE_SWITCH_CHARSET95
KEYCODE_BUTTON_A96
KEYCODE_BUTTON_B97
KEYCODE_BUTTON_C98
KEYCODE_BUTTON_X99
KEYCODE_BUTTON_Y100
KEYCODE_BUTTON_Z101
KEYCODE_BUTTON_L1102
KEYCODE_BUTTON_R1103
KEYCODE_BUTTON_L2104
KEYCODE_BUTTON_R2105
KEYCODE_BUTTON_THUMBL106
KEYCODE_BUTTON_THUMBR107
KEYCODE_BUTTON_START108
KEYCODE_BUTTON_SELECT109
KEYCODE_BUTTON_MODE110
KEYCODE_ESCAPE111ESC键
KEYCODE_FORWARD_DEL112删除键
KEYCODE_CTRL_LEFT113
KEYCODE_CTRL_RIGHT114
KEYCODE_CAPS_LOCK115大写锁定键
KEYCODE_SCROLL_LOCK116
KEYCODE_META_LEFT117
KEYCODE_META_RIGHT118
KEYCODE_FUNCTION119
KEYCODE_SYSRQ120
KEYCODE_BREAK121Break/Pause键
KEYCODE_MOVE_HOME122光标移动到开始键
KEYCODE_MOVE_END123光标移动到末尾键
KEYCODE_INSERT124
KEYCODE_FORWARD125
KEYCODE_MEDIA_PLAY126多媒体键 播放
KEYCODE_MEDIA_PAUSE127多媒体键 暂停
KEYCODE_MEDIA_CLOSE128多媒体键 关闭
KEYCODE_MEDIA_EJECT129多媒体键 弹出
KEYCODE_MEDIA_RECORD130多媒体键 录音
KEYCODE_F1131
KEYCODE_F2132
KEYCODE_F3133
KEYCODE_F4134
KEYCODE_F5135
KEYCODE_F6136
KEYCODE_F7137
KEYCODE_F8138
KEYCODE_F9139
KEYCODE_F10140
KEYCODE_F11141
KEYCODE_F12142
KEYCODE_NUM_LOCK143小键盘锁
KEYCODE_NUMPAD_0144
KEYCODE_NUMPAD_1145
KEYCODE_NUMPAD_2146
KEYCODE_NUMPAD_3147
KEYCODE_NUMPAD_4148
KEYCODE_NUMPAD_5149
KEYCODE_NUMPAD_6150
KEYCODE_NUMPAD_7151
KEYCODE_NUMPAD_8152
KEYCODE_NUMPAD_9153
KEYCODE_NUMPAD_DIVIDE154
KEYCODE_NUMPAD_MULTIPLY155
KEYCODE_NUMPAD_SUBTRACT156
KEYCODE_NUMPAD_ADD157
KEYCODE_NUMPAD_DOT158
KEYCODE_NUMPAD_COMMA159
KEYCODE_NUMPAD_ENTER160
KEYCODE_NUMPAD_EQUALS161
KEYCODE_NUMPAD_LEFT_PAREN162
KEYCODE_NUMPAD_RIGHT_PAREN163
KEYCODE_VOLUME_MUTE164扬声器静音键
KEYCODE_INFO165
KEYCODE_CHANNEL_UP166
KEYCODE_CHANNEL_DOWN167
KEYCODE_ZOOM_IN168放大键
KEYCODE_ZOOM_OUT169缩小键
KEYCODE_TV170
KEYCODE_WINDOW171
KEYCODE_GUIDE172
KEYCODE_DVR173
KEYCODE_BOOKMARK174
KEYCODE_CAPTIONS175
KEYCODE_SETTINGS176
KEYCODE_TV_POWER177
KEYCODE_TV_INPUT178
KEYCODE_STB_POWER179
KEYCODE_STB_INPUT180
KEYCODE_AVR_POWER181
KEYCODE_AVR_INPUT182
KEYCODE_PROG_RED183
KEYCODE_PROG_GREEN184
KEYCODE_PROG_YELLOW185
KEYCODE_PROG_BLUE186
KEYCODE_APP_SWITCH187
KEYCODE_BUTTON_1188
KEYCODE_BUTTON_2189
KEYCODE_BUTTON_3190
KEYCODE_BUTTON_4191
KEYCODE_BUTTON_5192
KEYCODE_BUTTON_6193
KEYCODE_BUTTON_7194
KEYCODE_BUTTON_8195
KEYCODE_BUTTON_9196
KEYCODE_BUTTON_10197
KEYCODE_BUTTON_11198
KEYCODE_BUTTON_12199
KEYCODE_BUTTON_13200
KEYCODE_BUTTON_14201
KEYCODE_BUTTON_15202
KEYCODE_BUTTON_16203
KEYCODE_LANGUAGE_SWITCH204
KEYCODE_MANNER_MODE205
KEYCODE_3D_MODE206
KEYCODE_CONTACTS207
KEYCODE_CALENDAR208
KEYCODE_MUSIC209
KEYCODE_CALCULATOR210
KEYCODE_ZENKAKU_HANKAKU211
KEYCODE_EISU212
KEYCODE_MUHENKAN213
KEYCODE_HENKAN214
KEYCODE_KATAKANA_HIRAGANA215
KEYCODE_YEN216
KEYCODE_RO217
KEYCODE_KANA218
KEYCODE_ASSIST219
KEYCODE_BRIGHTNESS_DOWN220
KEYCODE_BRIGHTNESS_UP221
KEYCODE_MEDIA_AUDIO_TRACK222
KEYCODE_SLEEP223
KEYCODE_WAKEUP224
KEYCODE_PAIRING225
KEYCODE_MEDIA_TOP_MENU226
KEYCODE_11227
KEYCODE_12228
KEYCODE_LAST_CHANNEL229
KEYCODE_TV_DATA_SERVICE230
KEYCODE_VOICE_ASSIST231
KEYCODE_TV_RADIO_SERVICE232
KEYCODE_TV_TELETEXT233
KEYCODE_TV_NUMBER_ENTRY234
KEYCODE_TV_TERRESTRIAL_ANALOG235
KEYCODE_TV_TERRESTRIAL_DIGITAL236
KEYCODE_TV_SATELLITE237
KEYCODE_TV_SATELLITE_BS238
KEYCODE_TV_SATELLITE_CS239
KEYCODE_TV_SATELLITE_SERVICE240
KEYCODE_TV_NETWORK241
KEYCODE_TV_ANTENNA_CABLE242
KEYCODE_TV_INPUT_HDMI_1243
KEYCODE_TV_INPUT_HDMI_2244
KEYCODE_TV_INPUT_HDMI_3245
KEYCODE_TV_INPUT_HDMI_4246
KEYCODE_TV_INPUT_COMPOSITE_1247
KEYCODE_TV_INPUT_COMPOSITE_2248
KEYCODE_TV_INPUT_COMPONENT_1249
KEYCODE_TV_INPUT_COMPONENT_2250
KEYCODE_TV_INPUT_VGA_1251
KEYCODE_TV_AUDIO_DESCRIPTION252
KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP253
KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN254
KEYCODE_TV_ZOOM_MODE255
KEYCODE_TV_CONTENTS_MENU256
KEYCODE_TV_MEDIA_CONTEXT_MENU257
KEYCODE_TV_TIMER_PROGRAMMING258
KEYCODE_HELP259
KEYCODE_NAVIGATE_PREVIOUS260
KEYCODE_NAVIGATE_NEXT261
KEYCODE_NAVIGATE_IN262
KEYCODE_NAVIGATE_OUT263
KEYCODE_STEM_PRIMARY264
KEYCODE_STEM_1265
KEYCODE_STEM_2266
KEYCODE_STEM_3267
KEYCODE_DPAD_UP_LEFT268
KEYCODE_DPAD_DOWN_LEFT269
KEYCODE_DPAD_UP_RIGHT270
KEYCODE_DPAD_DOWN_RIGHT271
KEYCODE_MEDIA_SKIP_FORWARD272
KEYCODE_MEDIA_SKIP_BACKWARD273
KEYCODE_MEDIA_STEP_FORWARD274
KEYCODE_MEDIA_STEP_BACKWARD275
KEYCODE_SOFT_SLEEP276
KEYCODE_CUT277
KEYCODE_COPY278
KEYCODE_PASTE279
KEYCODE_SYSTEM_NAVIGATION_UP280
KEYCODE_SYSTEM_NAVIGATION_DOWN281
KEYCODE_SYSTEM_NAVIGATION_LEFT282
KEYCODE_SYSTEM_NAVIGATION_RIGHT283

以上就是Flutter TV Android端开发技巧详细教程的详细内容,更多关于Flutter TV Android端开发的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

FlutterTVAndroid端开发技巧详细教程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

FlutterTVAndroid端开发技巧详细教程

这篇文章主要为大家介绍了FlutterTVAndroid端开发技巧详细教程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-12-09

Javaservlet后端开发超详细教程

Servlet指在服务器端执行的一段Java代码,可以接收用户的请求和返回给用户响应结果,下面这篇文章主要给大家介绍了关于Java.servlet生命周期的相关资料,需要的朋友可以参考下
2023-02-08

使用Element进行前端开发的详细图文教程

众所周知Element是一套Vue.js后台组件库,它能够帮助你更轻松更快速地开发后台项目,下面这篇文章主要给大家介绍了关于使用Element进行前端开发的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
2022-11-13

mathtype的下载与使用技巧超详细教程

这篇文章主要介绍了mathtype的下载与使用超详细教程,包括mathtype使用技巧常用快捷键,本文给大家讲解的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-01-29

rust开发环境配置详细教程

rust是一门比较新的编程语言,2015年5月15日,Rust编程语言核心团队正式宣布发布Rust1.0版本,这篇文章主要介绍了rust开发环境配置,需要的朋友可以参考下
2022-12-21

Rust语言开发环境搭建详细教程(图文教程)

本教程提供了一个详细的分步指南,帮助初学者在不同操作系统上搭建Rust开发环境。涵盖从安装Rust工具链到配置环境变量、安装编辑器或IDE、创建项目、编写代码、编译和运行代码以及调试代码等所有步骤。还提供了附加提示,包括使用Rustup管理安装和使用Cargo管理依赖项。
Rust语言开发环境搭建详细教程(图文教程)
2024-04-02

MySQL高级开发中视图的详细教程

目录1.介绍2.语法3.检查选项4.视图的更新5.视图作用6.案例1.介绍视图(View)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视 图的查询中使用的表,并且是在使用视图时动态生成的。通俗的讲,视图只保
2023-01-09

pycharm使用docker容器开发的详细教程

这篇文章主要介绍了pycharm使用docker容器开发的详细教程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-01-05

iOS开发教程之常见的性能优化技巧

前言 性能问题的主要原因是什么,原因有相同的,也有不同的,但归根到底,不外乎内存使用、代码效率、合适的策略逻辑、代码质量、安装包体积这一类问题。但从用户体验的角度去思考,当我们置身处地得把自己当做用户去玩一款应用时候,那么都会在意什么呢?假
2022-06-02

阿里云服务器开启端口的详细教程

阿里云服务器是企业级云服务器产品,拥有丰富的安全性能和灵活的配置选项。本文将详细讲解如何在阿里云服务器上开启端口。在阿里云服务器上开启端口是非常常见的操作,因为很多应用和服务都需要通过端口来接收和发送数据。这篇文章将为你提供详细的步骤和教程,让你轻松开启端口。步骤一:登录阿里云服务器首先,你需要登录你的阿里云服务
阿里云服务器开启端口的详细教程
2023-12-10

微信小程序开发(超详细保姆式教程)

介绍: 微信里面app,16年推出 竞品:支付宝小程序,钉钉,美团,头条,抖音qq小程序 优点 1,在微信里面自由分享,2,不用下载app,3,能快速的开发,使用微信的api接口 开发者 内存,源码,图片,存储,接口与数据都有限制
2023-08-16

PyCharm详细配置教程:让Python开发更高效!

PyCharm是一款由JetBrains公司推出的专业的Python集成开发环境(IDE),它提供了丰富的功能和强大的工具,能够帮助Python开发者提高开发效率。本文将详细介绍如何在PyCharm中进行配置,让Python开发变得更加高效
PyCharm详细配置教程:让Python开发更高效!
2024-02-22

阿里云服务器打开22端口的详细教程

在使用阿里云服务器的过程中,可能需要通过22端口进行远程连接。但很多用户在尝试连接时,发现无法打开22端口。那么,如何打开阿里云服务器的22端口呢?本文将为你提供详细的步骤和方法。步骤1:登录阿里云服务器首先,你需要在浏览器中输入你的阿里云服务器的IP地址和用户名密码,登录你的阿里云服务器。步骤2:查看服务器状态
阿里云服务器打开22端口的详细教程
2023-11-15

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录