Flutter开发之支持放大镜的输入框功能实现

目录
  • 功能需求
  • 需求调研
  • 需求实现
    • 源码解读
    • 功能复刻
    • 最终效果

功能需求

最近需求开发中遇到一个Flutter开发问题,为了优化用户输入体验。产品同学希望能够在输入框支持在移动光标过程中可以出现放大镜功能。原先以为是一个小需求,因为原生系统上iOS和安卓印象中是自带这个功能的。在实施开发时才发现原来并不是这样的,Flutter好像并没有去支持原有的功能。

需求调研

为了确认官方是否支持了输入框放大镜功能,去github项目上搜索issue后发现这个问题在18年就有人提到过,但官方却一直没有去支持实现。

既然官方没有支持,秉承有轮子我就用的思想继续通过github搜索是否有开发者自定义实现了这个功能。

搜索Magnifier找到了一篇文章是对放大镜的实现,但他并不是在输入框上的实现,只对屏幕手势触摸的地方进行放大。

因为找不到完全实现输入框放大镜功能,那么只能自行去实现该功能了。可以根据Magnifier来为输入框实现放大镜功能。

需求实现

通过对TextField的使用会发现,当使用光标双击或是长按会出现TextToolBar功能栏,随着光标的移动,上方的编辑栏也会跟着光标进行移动。这个发现正好能够在放大镜功能上运用:跟随光标移动+放大就能够实现最终期望的效果了。

源码解读

那么在功能实现之前就需要阅读TextField源码了解光标上方的编辑栏是如何实现并且能够跟随光标的。

PS:源码解析使用的是extended_text_field,主因是项目中使用了富文本输入和显示。

ExtendedTextField输入框组件源码找到ExtendedEditableText中视图build方法可以看到CompositedTransformTarget_toolbarLayerLink。而这两个已经是实现放大镜功能的关键信息了。

关于CompositedTransformTarget的使用可以在网上搜到很多,作用是来绑定两个View视图。除了CompositedTransformTarget之外还有CompositedTransformFollower。简单理解就是CompositedTransformFollower是绑定者,CompositedTransformTarget是被绑定者,前者跟随后者。_toolbarLayerLink就是跟随光标操作栏的绑定媒介。

return CompositedTransformTarget(
  link: _toolbarLayerLink, // 操作工具
  child: Semantics(
    ...
    child: _Editable(
      key: _editableKey,
      startHandleLayerLink: _startHandleLayerLink, //左边光标位置
      endHandleLayerLink: _endHandleLayerLink, //右边光标位置
      textSpan: _buildTextSpan(context),
      value: _value,
      cursorColor: _cursorColor,
      ......
    ),
  ),
);

通过源码查询找到_toolbarLayerLink另一个使用者ExtendedTextSelectionOverlay

void createSelectionOverlay({ //创建操作栏
  ExtendedRenderEditable? renderObject,
  bool showHandles = true,
}) {
  _selectionOverlay = ExtendedTextSelectionOverlay(
    clipboardStatus: _clipboardStatus,
    context: context,
    value: _value,
    debugRequiredFor: widget,
    toolbarLayerLink: _toolbarLayerLink,
    startHandleLayerLink: _startHandleLayerLink,
    endHandleLayerLink: _endHandleLayerLink,
    renderObject: renderObject ?? renderEditable,
    selectionControls: widget.selectionControls,
   .....
  );
    ...

通过源码查询可以找到CompositedTransformFollower组件使用,可以通过代码看到selectionControls!.buildToolbar就是编辑栏的实现。

return Directionality(
  textDirection: Directionality.of(this.context),
  child: FadeTransition(
    opacity: _toolbarOpacity,
    child: CompositedTransformFollower( // 操作栏的跟踪组件
      link: toolbarLayerLink,
      showWhenUnlinked: false,
      offset: -editingRegion.topLeft,
      child: Builder(
        builder: (BuildContext context) {
          return selectionControls!.buildToolbar(
            context,
            editingRegion,
            renderObject.preferredLineHeight,
            midpoint,
            endpoints,
            selectionDelegate!,
            clipboardStatus!,
            renderObject.lastSecondaryTapDownPosition,
          );
        },
      ),
    ),
  ),
);

然后返回去找selectionControls是如何实现的。在_ExtendedTextFieldStatebuild方法中可以找到textSelectionControls默认创建。由于安卓和iOS平台存在差异性,因此有cupertinoTextSelectionControlsmaterialTextSelectionControls两个selectionControls。

switch (theme.platform) {
  case TargetPlatform.iOS:
    final CupertinoThemeData cupertinoTheme = CupertinoTheme.of(context);
    forcePressEnabled = true;
    textSelectionControls ??= cupertinoTextSelectionControls;
    ......
    break;

     ......

  case TargetPlatform.android:
  case TargetPlatform.fuchsia:
    forcePressEnabled = false;
    textSelectionControls ??= materialTextSelectionControls;
   .....
    break;
    ....
}

这里就只看MaterialTextSelectionControls源码实现。布局实现在_TextSelectionControlsToolbar中。_TextSelectionHandlePainter是绘制光标样式的方法。

 @override
  Widget build(BuildContext context) {
      // 左右光标的定位位置
    final TextSelectionPoint startTextSelectionPoint = widget.endpoints[0];
    // 这里做了判断是否是两个光标
    final TextSelectionPoint endTextSelectionPoint = widget.endpoints.length > 1
      ? widget.endpoints[1]
      : widget.endpoints[0];
    final Offset anchorAbove = Offset(
      widget.globalEditableRegion.left + widget.selectionMidpoint.dx,
      widget.globalEditableRegion.top + startTextSelectionPoint.point.dy - widget.textLineHeight - _kToolbarContentDistance,
    );
    final Offset anchorBelow = Offset(
      widget.globalEditableRegion.left + widget.selectionMidpoint.dx,
      widget.globalEditableRegion.top + endTextSelectionPoint.point.dy + _kToolbarContentDistanceBelow,
    );

   ....

    return TextSelectionToolbar(
      anchorAbove: anchorAbove, // 左边光标
      anchorBelow: anchorBelow,// 右边光标
      children: itemDatas.asMap().entries.map((MapEntry<int, _TextSelectionToolbarItemData> entry) {
        return TextSelectionToolbarTextButton(
          padding: TextSelectionToolbarTextButton.getPadding(entry.key, itemDatas.length),
          onPressed: entry.value.onPressed,
          child: Text(entry.value.label),
        );
      }).toList(), // 每个编辑操作的按钮功能
    );
  }
}
/// 安卓选中样式绘制(默认是圆点加上一个箭头)
class _TextSelectionHandlePainter extends CustomPainter {
  _TextSelectionHandlePainter({ required this.color });

  final Color color;

  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint()..color = color;
    final double radius = size.width/2.0;
    final Rect circle = Rect.fromCircle(center: Offset(radius, radius), radius: radius);
    final Rect point = Rect.fromLTWH(0.0, 0.0, radius, radius);
    final Path path = Path()..addOval(circle)..addRect(point);
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(_TextSelectionHandlePainter oldPainter) {
    return color != oldPainter.color;
  }
}

功能复刻

了解源码功能之后就能拷贝MaterialTextSelectionControls实现来完成放大镜功能了。同样是继承TextSelectionControls,实现MaterialMagnifierControls功能。

主要修改点在_MagnifierControlsToolbar的实现以及MaterialMagnifier功能

MagnifierControlsToolbar

其中的build方法返回了widget.endpoints光标的定位信息,定位信息去计算出偏移量。最后将两个光标信息入参到MaterialMagnifier组件。

const double _kHandleSize = 22.0;

const double _kToolbarContentDistanceBelow = _kHandleSize - 2.0;
const double _kToolbarContentDistance = 8.0;

class MaterialMagnifierControls extends TextSelectionControls {

  @override
  Size getHandleSize(double textLineHeight) =>
      const Size(_kHandleSize, _kHandleSize);

  @override
  Widget buildToolbar(
    BuildContext context,
    Rect globalEditableRegion,
    double textLineHeight,
    Offset selectionMidpoint,
    List<TextSelectionPoint> endpoints,
    TextSelectionDelegate delegate,
    ClipboardStatusNotifier clipboardStatus,
    Offset? lastSecondaryTapDownPosition,
  ) {
    return _MagnifierControlsToolbar(
      globalEditableRegion: globalEditableRegion,
      textLineHeight: textLineHeight,
      selectionMidpoint: selectionMidpoint,
      endpoints: endpoints,
      delegate: delegate,
      clipboardStatus: clipboardStatus,
    );
  }

  @override
  Widget buildHandle(
      BuildContext context, TextSelectionHandleType type, double textHeight,
      [VoidCallback? onTap, double? startGlyphHeight, double? endGlyphHeight]) {
    return const SizedBox();
  }

  @override
  Offset getHandleAnchor(TextSelectionHandleType type, double textLineHeight,
      [double? startGlyphHeight, double? endGlyphHeight]) {
    switch (type) {
      case TextSelectionHandleType.left:
        return const Offset(_kHandleSize, 0);
      case TextSelectionHandleType.right:
        return Offset.zero;
      default:
        return const Offset(_kHandleSize / 2, -4);
    }
  }
}

class _MagnifierControlsToolbar extends StatefulWidget {
  const _MagnifierControlsToolbar({
    Key? key,
    required this.clipboardStatus,
    required this.delegate,
    required this.endpoints,
    required this.globalEditableRegion,
    required this.selectionMidpoint,
    required this.textLineHeight,
  }) : super(key: key);

  final ClipboardStatusNotifier clipboardStatus;
  final TextSelectionDelegate delegate;
  final List<TextSelectionPoint> endpoints;
  final Rect globalEditableRegion;
  final Offset selectionMidpoint;
  final double textLineHeight;

  @override
  _MagnifierControlsToolbarState createState() =>
      _MagnifierControlsToolbarState();
}

class _MagnifierControlsToolbarState extends State<_MagnifierControlsToolbar>
    with TickerProviderStateMixin {

  Offset offset1 = Offset.zero;
  Offset offset2 = Offset.zero;
  void _onChangedClipboardStatus() {
    setState(() {
    });
  }

  @override
  void initState() {
    super.initState();
    widget.clipboardStatus.addListener(_onChangedClipboardStatus);
    widget.clipboardStatus.update();
  }

  @override
  void didUpdateWidget(_MagnifierControlsToolbar oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.clipboardStatus != oldWidget.clipboardStatus) {
      widget.clipboardStatus.addListener(_onChangedClipboardStatus);
      oldWidget.clipboardStatus.removeListener(_onChangedClipboardStatus);
    }
    widget.clipboardStatus.update();
  }

  @override
  void dispose() {
    super.dispose();
    if (!widget.clipboardStatus.disposed) {
      widget.clipboardStatus.removeListener(_onChangedClipboardStatus);
    }
  }

  @override
  Widget build(BuildContext context) {
    TextSelectionPoint point = widget.endpoints[0];
    if(widget.endpoints.length > 1){
      if(offset1 != widget.endpoints[0].point){
        point =  widget.endpoints[0];
        offset1 = point.point;
      }
      if(offset2 != widget.endpoints[1].point){
        point =  widget.endpoints[1];
        offset2 = point.point;
      }
    }

    final TextSelectionPoint startTextSelectionPoint = point;

    final Offset anchorAbove = Offset(
      widget.globalEditableRegion.left + startTextSelectionPoint.point.dx,
      widget.globalEditableRegion.top +
          startTextSelectionPoint.point.dy -
          widget.textLineHeight -
          _kToolbarContentDistance,
    );
    final Offset anchorBelow = Offset(
      widget.globalEditableRegion.left + startTextSelectionPoint.point.dx,
      widget.globalEditableRegion.top +
          startTextSelectionPoint.point.dy +
          _kToolbarContentDistanceBelow,
    );

    return  MaterialMagnifier(
        anchorAbove: anchorAbove,
        anchorBelow: anchorBelow,
        textLineHeight: widget.textLineHeight,
    );
  }
}

final TextSelectionControls materialMagnifierControls =
    MaterialMagnifierControls();

MaterialMagnifier

MaterialMagnifier是参考Widget Magnifier放大镜的实现。这里是引入了安卓的一些布局参数来实现,iOS是另外定制了布局参数可以参考Flutter官方源码定制iOS布局。

放大镜实现方法主要是BackdropFilterImageFilter来实现的,根据Matrix4scaletranslate操作完成放大功能。

const double _kToolbarScreenPadding = 8.0;
const double _kToolbarHeight = 44.0;

class MaterialMagnifier extends StatelessWidget {

  const MaterialMagnifier({
    Key? key,
    required this.anchorAbove,
    required this.anchorBelow,
    required this.textLineHeight,
    this.size = const Size(90, 50),
    this.scale = 1.7,
  }) : super(key: key);

  final Offset anchorAbove;
  final Offset anchorBelow;

  final Size size;
  final double scale;
  final double textLineHeight;

  @override
  Widget build(BuildContext context) {
    final double paddingAbove =
        MediaQuery.of(context).padding.top + _kToolbarScreenPadding;
    final double availableHeight = anchorAbove.dy - paddingAbove;
    final bool fitsAbove = _kToolbarHeight <= availableHeight;
    final Offset localAdjustment = Offset(_kToolbarScreenPadding, paddingAbove);
    final Matrix4 updatedMatrix = Matrix4.identity()
      ..scale(1.1,1.1)
      ..translate(0.0,-50.0);
    Matrix4 _matrix = updatedMatrix;
    return Container(
      child: Padding(
        padding: EdgeInsets.fromLTRB(
          _kToolbarScreenPadding,
          paddingAbove,
          _kToolbarScreenPadding,
          _kToolbarScreenPadding,
        ),
        child: Stack(
          children: <Widget>[
            CustomSingleChildLayout(
              delegate: TextSelectionToolbarLayoutDelegate(
                anchorAbove: anchorAbove - localAdjustment,
                anchorBelow: anchorBelow - localAdjustment,
                fitsAbove: fitsAbove,
              ),
              child: ClipRRect(
                borderRadius: BorderRadius.circular(10),
                child: BackdropFilter(
                  filter: ImageFilter.matrix(_matrix.storage),
                  child: CustomPaint(
                    painter: const MagnifierPainter(color: Color(0xFFdfdfdf)),
                    size: size,
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

交互优化

实现放大镜功能之外还需要控制显示,由于在拖动状态下才显示放大镜,隐藏操作栏功能,因此需要去监听手势状态信息。

手势监听是在_TextSelectionHandleOverlayState中,需要去监听onPanStartonPanUpdateonPanEndonPanCancel这几个状态。

状态 行动
onPanStart 隐藏操作栏、显示放大镜
onPanUpdate 显示放大镜,获取到偏移信息
onPanEnd 显示操作栏、隐藏放大镜
onPanCancel 显示操作栏、隐藏放大镜
final Widget child = GestureDetector(
  behavior: HitTestBehavior.translucent,
  dragStartBehavior: widget.dragStartBehavior,
  onPanStart: _handleDragStart,
  onPanUpdate: _handleDragUpdate,
  onPanEnd: _handleDragEnd,
  onPanCancel: _handleDragCancel,
  onTap: _handleTap,
  child: Padding(
    padding: EdgeInsets.only(
      left: padding.left,
      top: padding.top,
      right: padding.right,
      bottom: padding.bottom,
    ),
    child: widget.selectionControls!.buildHandle(
      context,
      type,
      widget.renderObject.preferredLineHeight,
          () {},
    ),
  ),
);

在开始拓展手势时展示放大镜,隐藏操作。_builderMagnifier嵌套在OverlayEntry组件在Overlay上插入,实现方式是和操作栏完全一样的。

void _handleDragStart(DragStartDetails details) {
  final Size handleSize = widget.selectionControls!.getHandleSize(
    widget.renderObject.preferredLineHeight,
  );
  _dragPosition = details.globalPosition + Offset(0.0, -handleSize.height);
  widget.showMagnifierBarFunc(); // 回调展示放大镜功能
  toolBarRecover = widget.hideToolbarFunc();
}
void showMagnifierBar() {
  assert(_magnifier == null);
  _magnifier = OverlayEntry(builder: _builderMagnifier);
  Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor)!
      .insert(_magnifier!);
}

同理在拖拽结束时去隐藏放大镜,重新创建操作栏恢复显示。

void _handleDragEnd(DragEndDetails details) {
  widget.hideMagnifierBarFunc();
  if (toolBarRecover) {
    widget.showToolbarFunc();
    toolBarRecover = false;
  }
}

void hideMagnifierBar() {
  if (_magnifier != null) {
    _magnifier!.remove();
    _magnifier = null;
  }
}

最终效果

最后实现效果如下,通过移动光标可显示放大镜功能,松开手势就是操作栏显示恢复。

以上就是Flutter开发之支持放大镜的输入框功能实现的详细内容,更多关于Flutter的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android轮播图点击图片放大效果的实现方法

    前言 最近项目中需要实现轮播图显示商品图片,当用户点击商品图片的时候,需要图片放大显示,当然用户还能进行多张图片的滑动切换,放大,缩小图片等操作,实现起来相对还是比较简单的,话不多说,咱们是用代码说话的,直接上代码. 实现步骤: 1.效果图的展示 2.项目中添加相关的依赖 3.主界面实现轮播图的效果 4.点击轮播图进入图片放大展示页面 5.图片放大展示页面所需的适配器 6.获取fragment需要展示图片的url 7.图片缩放时遇到Bug解决 实现过程: 1.效果图的展示 2.项目中添加相关的依

  • Android实现图片点击放大

    本文实例为大家分享了Android实现图片点击放大的具体代码,供大家参考,具体内容如下 在我的项目中,有点击图片banner后放大浏览的功能.我的做法就是创建一个专门的图片显示Activity,布局里面用ViewPage,这样就能控制图片的左右滑动,并且控制首先显示第几张图片. 功能是ok的,显示也是正常的.但我花费了好几天的时间来实现.完善这个功能. ShowMoreImageActivity /** * 图片放大 */ public class ShowMoreImageActivity e

  • 简单实现Android放大镜效果

    利用之前学过的图形图像绘画技术和图片添加特效技术,我们来实现一个Android放大镜的简单应用. 最终效果如图 具体实现: 用来显示自定义的绘图类的布局文件 res/layout/main.xml: <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns

  • Android实现放大镜效果的方法实例(附源码)

    前言 应该有很多用过英语应用的同学都看多一个放大镜的效果,就是选中一段文字后,会有一个放大镜,这个究竟怎么实现的呢,我们今天来分析分析. 源码分析 public class ShaderView extends View { private final Bitmap bitmap; private final ShapeDrawable drawable; // 放大镜的半径 private static final int RADIUS = 80; // 放大倍数 private static

  • Android放大镜的实现代码

    快三个月了没写博客了,因为工作调动,很多经验.心得都没有时间记录下来.现在时间稍微充裕了点,我会尽量抽时间将之前想写而没写的东西补上.进入正题.去年某个时候,我偶然看到一篇文章,讲android里面放大镜的实现.文章很乱,没有格式,基本上属于看不下去的那种.虽然体裁很有意思,但是我也没有足够的内力把它看完.不过看到一句关键的话,说是使用带圆形的Drawable.这句话就够了,他下面写的一堆东西我也懒得看,于是就自己开始尝试,然后就做出来了.现在代码贴出来分享.Java代码 复制代码 代码如下:

  • android 放大镜ShapeDrawable妙用分享

    首先,ShapeDrawable构造的时候可以指定描画的形状, 其次,可以通过shape.getPaint().setShader();指定Shader,shader可以接受一个图片和matrix 所以问题就顺利的解决了:) 具体实现如下:[java] 复制代码 代码如下: float scale = 1.2f; int cx = 224; int cy = 357; int r = 200; // 指定形状创建一个ShapeDrawable  ShapeDrawable shape=new S

  • Flutter开发之支持放大镜的输入框功能实现

    目录 功能需求 需求调研 需求实现 源码解读 功能复刻 最终效果 功能需求 最近需求开发中遇到一个Flutter开发问题,为了优化用户输入体验.产品同学希望能够在输入框支持在移动光标过程中可以出现放大镜功能.原先以为是一个小需求,因为原生系统上iOS和安卓印象中是自带这个功能的.在实施开发时才发现原来并不是这样的,Flutter好像并没有去支持原有的功能. 需求调研 为了确认官方是否支持了输入框放大镜功能,去github项目上搜索issue后发现这个问题在18年就有人提到过,但官方却一直没有去支

  • iOS实现聊天输入框功能

    经常使用微信聊天,没事儿就会想输入框的实现过程,所以抽空,也实现了一个输入框的功能: 经过封装,使用就非常的简单了,在需要的VC中,实现方法如下: - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor colorWithRed:0.92 green:0.92 blue:0.92 alpha:1.00]; self.keyView = [[DKSKeyboardView alloc] init

  • 如何使用Flutter开发一款电影APP详解

    前言 使用Flutter开发一款App是一件非常愉快的事情,其出色的性能.跨多端以及数量众多的原生组件都是我们选择Flutter的理由!今天我们就来使用Flutter开发一款电影类的App,先看下App的截图. 从main.dart开始 在Flutter里main.dart是应用开始的地方: import 'package:flutter/material.dart'; import 'package:movie/utils/router.dart' as router; void main()

  • 使用Flutter开发的抖音国际版实例代码详解

    简介 最近花了两天时间研究使用Flutter开发一个抖音国际版. 个人感觉使用Flutter开发app快得不要不要的额. 两天就基本可以开发个大概出来. 最主要是热重载,太方便实时调整UI布局了. 相应速度极快. 如下图: 主要项目架构 详细说明一下,开发主要在lib文件夹 pubspec.yaml是配置插件的位置,如http: ^0.12.0+4,类似依赖组件. common文件夹存放的是重写的网络组件,以及图标组件icons.dart config文件夹存放的api.dart,wei调用的a

  • flutter实现带删除动画的listview功能

    个人开发app中,需要开发一个带有删除功能的ListView 效果如下 需求动画分析 列表可以滚动用listView, 有两个动画,第一个动画是透明度变化,第二个是size变化 是顺序执行 实现过程 新建一个动画页面进行单独控制 记得用statefulwidget类,这第二个动画之间涉及到页面刷新切换widget 记得with tickerproviderstatemixin 这个是动画类状态管理的必备 class AnimationListItem extends StatefulWidget

  • Flutter 开发一个登录页面

    业务逻辑 为了演示登录跳转,在分类浏览先做了一个简单的按钮,点击跳转到登录页面.实际的 App 中,通常会是触发某些需要登录才能查看的操作后再跳转到登录界面. 布局分析 界面如上图所示,从界面上看,整体内容区域是居中的,内容的布局是一个简单的列式布局,包括了顶部的一个 Logo(通常是 App图标),再往下是两个文本输入框,最后是登录按钮.整体布局比较简单,使用 Center 下嵌一个Column 进行列布局即可. 图片圆形裁剪 在 Flutter 中实行图片圆形裁剪有两个方式,一是使用外层的容

  • Angular4实现动态添加删除表单输入框功能

    首先介绍一下实现的效果,就是单一表单能实现添加其他的,也能删除 代码如下: <h5>动态添加表单</h5> <div class="form"> <div class="form-group form-group-sm" *ngFor="let i of login"> <label class="col-form-label">用户名</label> &

  • iOS开发微信收款到账语音提醒功能思路详解

    一.背景 为了解决小商户老板们在频繁交易中不方便核对.确认到账的痛点,产品MM提出了新版本需要支持收款到账语音提醒功能.这篇文章总结了开发过程中遇到的坑和一些小技巧. 二.技术方案 后台唤醒App 收款到账语音提醒需要收款方在收到款后,播放一段TTS合成语音播报金额,微信在前台时可以通过模板消息将需要播报的金额带下来,再请求TTS数据并播放,但是app在挂起或者被kill掉的情况下要如何请求语音数据并播放呢? iOS提供了两种方式唤醒处于挂起或已经被kill掉的app.分别是Silent Not

  • 基于jQuery下拉选择框插件支持单选多选功能代码

    由于最近项目的需求,需要做一个下拉选择框的插件,支持单选显示表单数据,多选显示表格数据,该插件主要运用了jQuery与jqgrid以及easyui. 下面给大家展示下效果图,如果大家感觉还不错,请参考实现代码: 多选:呈现列表 具体代码如下所示: /** *下拉框插件-chooseList *调用插件的方式以及格式: * 1.首先你需要创建一个div面板,给div定义ID * 2.在你所需要的地方调用插件: * 参数说明: * $("#divID").chooseList({ * qu

  • Android开发之文本内容自动朗读功能实现方法

    本文实例讲述了Android开发之文本内容自动朗读功能实现方法.分享给大家供大家参考,具体如下: Android提供了自动朗读支持.自动朗读支持可以对指定文本内容进行朗读,从而发生声音:不仅如此,Android的自动朗读支持还允许把文本对应的音频录制成音频文件,方便以后播放.这种自动朗读支持的英文名称为TextToSpeech,简称TTS. 借助于TTS的支持,可以在应用程序中动态地增加音频输出,从而改善用户体验. Android的自动朗读支持主要通过TextTospeech来完成,该累提供了如

随机推荐