Flutter 更改ListView或ListWheelScrollView项目时如何实现轻微声音

Flutter 更改ListView或ListWheelScrollView项目时如何实现轻微声音,flutter,Flutter,我有一个非常简单的ListWheelScrollView,我在文本窗口小部件中将年份显示为元素,但对于UX来说,有轻微的项目更改声音是很好的 ListWheelScrollView( itemExtent: 80, onSelectedItemChanged: (int index) { setState(() { if (releaseEnd > i

我有一个非常简单的ListWheelScrollView,我在文本窗口小部件中将年份显示为元素,但对于UX来说,有轻微的项目更改声音是很好的

ListWheelScrollView(
                itemExtent: 80,
                onSelectedItemChanged: (int index) {
                  setState(() {
                    if (releaseEnd > index + 1950) {
                      releaseStart = index + 1950;
                    } else {
                      return null;
                    }
                  });
                },
                diameterRatio: 4.0,
                offAxisFraction: -3.0,
                physics: BouncingScrollPhysics(),
                children: years
                    .map((element) => RotatedBox(
                          quarterTurns: 3,
                          child: Container(
                            decoration: element == releaseStart
                                ? BoxDecoration(
                                    borderRadius: BorderRadius.all(
                                      Radius.circular(4.0),
                                    ),
                                    color: Colors.blue,
                                    border: Border.all(
                                        color: Colors.blue, width: 2),
                                    shape: BoxShape.rectangle,
                                  )
                                : null,
                            padding: EdgeInsets.all(5),
                            child: Text(
                              element.toString(),
                              textAlign: TextAlign.center,
                              style: Theme.of(context)
                                  .textTheme
                                  .subtitle
                                  .copyWith(
                                      color: element == releaseStart
                                          ? Colors.white
                                          : Colors.black54,
                                      letterSpacing: 2),
                            ),
                          ),
                        ))
                    .toList(),
              ),
现在可以使用声音来更改其元素了吗?

您可以使用声音从资源或url播放声音

在ListWheelScrollView中,当居中项目更改时,它将播放audio.mp3,
因此,在onSelectedItemChanged中添加

audioCache.play('audio.mp3')
用于资产的示例代码段

import 'package:audioplayers/audio_cache.dart';
...
AudioCache audioCache = AudioCache();
...
_btn('Play', () => audioCache.play('audio.mp3')),
...
Widget _btn(String txt, VoidCallback onPressed) {
   return ButtonTheme(minWidth: 48.0, child: RaisedButton(child: Text(txt), onPressed: onPressed));
}
完整代码

import 'dart:async';
import 'dart:io';

import 'package:audioplayers/audio_cache.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:path_provider/path_provider.dart';

import 'player_widget.dart';

typedef void OnError(Exception exception);

const kUrl1 = 'https://luan.xyz/files/audio/ambient_c_motion.mp3';
const kUrl2 = 'https://luan.xyz/files/audio/nasa_on_a_mission.mp3';
const kUrl3 = 'http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1xtra_mf_p';

void main() {
  runApp(new MaterialApp(home: new ExampleApp()));
}

class ExampleApp extends StatefulWidget {
  @override
  _ExampleAppState createState() => new _ExampleAppState();
}

class _ExampleAppState extends State<ExampleApp> {
  AudioCache audioCache = AudioCache();
  AudioPlayer advancedPlayer = AudioPlayer();
  String localFilePath;

  Future _loadFile() async {
    final bytes = await readBytes(kUrl1);
    final dir = await getApplicationDocumentsDirectory();
    final file = File('${dir.path}/audio.mp3');

    await file.writeAsBytes(bytes);
    if (await file.exists()) {
      setState(() {
        localFilePath = file.path;
      });
    }
  }

  Widget _tab(List<Widget> children) {
    return Center(
      child: Container(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: children.map((w) => Container(child: w, padding: EdgeInsets.all(6.0))).toList(),
        ),
      ),
    );
  }

  Widget _btn(String txt, VoidCallback onPressed) {
    return ButtonTheme(minWidth: 48.0, child: RaisedButton(child: Text(txt), onPressed: onPressed));
  }

  Widget remoteUrl() {
    return SingleChildScrollView(
      child: _tab([
        Text(
          'Sample 1 ($kUrl1)',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
        PlayerWidget(url: kUrl1),
        Text(
          'Sample 2 ($kUrl2)',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
        PlayerWidget(url: kUrl2),
        Text(
          'Sample 3 ($kUrl3)',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
        PlayerWidget(url: kUrl3),
        Text(
          'Sample 4 (Low Latency mode) ($kUrl1)',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
        PlayerWidget(url: kUrl1, mode: PlayerMode.LOW_LATENCY),
      ]),
    );
  }

  Widget localFile() {
    return _tab([
      Text('File: $kUrl1'),
      _btn('Download File to your Device', () => _loadFile()),
      Text('Current local file path: $localFilePath'),
      localFilePath == null ? Container() : PlayerWidget(url: localFilePath, isLocal: true),
    ]);
  }

  Widget localAsset() {
    return _tab([
      Text('Play Local Asset \'audio.mp3\':'),
      _btn('Play', () => audioCache.play('audio.mp3')),
      Text('Loop Local Asset \'audio.mp3\':'),
      _btn('Loop', () => audioCache.loop('audio.mp3')),
      Text('Play Local Asset \'audio2.mp3\':'),
      _btn('Play', () => audioCache.play('audio2.mp3')),
      Text('Play Local Asset In Low Latency \'audio.mp3\':'),
      _btn('Play', () => audioCache.play('audio.mp3', mode: PlayerMode.LOW_LATENCY)),
      Text('Play Local Asset In Low Latency \'audio2.mp3\':'),
      _btn('Play', () => audioCache.play('audio2.mp3', mode: PlayerMode.LOW_LATENCY)),
      getLocalFileDuration(),
    ]);
  }

  Future<int> _getDuration() async {
    File audiofile = await audioCache.load('audio2.mp3');
    await advancedPlayer.setUrl(
      audiofile.path,
      isLocal: true,
    );
    int duration = await Future.delayed(Duration(seconds: 2), () => advancedPlayer.getDuration());
    return duration;
  }

  getLocalFileDuration() {
    return FutureBuilder<int>(
      future: _getDuration(),
      builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.none:
            return Text('No Connection...');
          case ConnectionState.active:
          case ConnectionState.waiting:
            return Text('Awaiting result...');
          case ConnectionState.done:
            if (snapshot.hasError) return Text('Error: ${snapshot.error}');
            return Text('audio2.mp3 duration is: ${Duration(milliseconds: snapshot.data)}');
        }
        return null; // unreachable
      },
    );
  }

  Widget notification() {
    return _tab([
      Text('Play notification sound: \'messenger.mp3\':'),
      _btn('Play', () => audioCache.play('messenger.mp3', isNotification: true)),
    ]);
  }

  Widget advanced() {
    return _tab([
      Column(children: [
        Text('Source Url'),
        Row(children: [
          _btn('Audio 1', () => advancedPlayer.setUrl(kUrl1)),
          _btn('Audio 2', () => advancedPlayer.setUrl(kUrl2)),
          _btn('Stream', () => advancedPlayer.setUrl(kUrl3)),
        ], mainAxisAlignment: MainAxisAlignment.spaceEvenly),
      ]),
      Column(children: [
        Text('Release Mode'),
        Row(children: [
          _btn('STOP', () => advancedPlayer.setReleaseMode(ReleaseMode.STOP)),
          _btn('LOOP', () => advancedPlayer.setReleaseMode(ReleaseMode.LOOP)),
          _btn('RELEASE', () => advancedPlayer.setReleaseMode(ReleaseMode.RELEASE)),
        ], mainAxisAlignment: MainAxisAlignment.spaceEvenly),
      ]),
      new Column(children: [
        Text('Volume'),
        Row(children: [
          _btn('0.0', () => advancedPlayer.setVolume(0.0)),
          _btn('0.5', () => advancedPlayer.setVolume(0.5)),
          _btn('1.0', () => advancedPlayer.setVolume(1.0)),
          _btn('2.0', () => advancedPlayer.setVolume(2.0)),
        ], mainAxisAlignment: MainAxisAlignment.spaceEvenly),
      ]),
      new Column(children: [
        Text('Control'),
        Row(children: [
          _btn('resume', () => advancedPlayer.resume()),
          _btn('pause', () => advancedPlayer.pause()),
          _btn('stop', () => advancedPlayer.stop()),
          _btn('release', () => advancedPlayer.release()),
        ], mainAxisAlignment: MainAxisAlignment.spaceEvenly),
      ]),
      new Column(children: [
        Text('Seek in milliseconds'),
        Row(children: [
          _btn('100ms', () => advancedPlayer.seek(Duration(milliseconds: 100))),
          _btn('500ms', () => advancedPlayer.seek(Duration(milliseconds: 500))),
          _btn('1s', () => advancedPlayer.seek(Duration(seconds: 1))),
          _btn('1.5s', () => advancedPlayer.seek(Duration(milliseconds: 1500))),
        ], mainAxisAlignment: MainAxisAlignment.spaceEvenly),
      ]),
    ]);
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 5,
      child: Scaffold(
        appBar: AppBar(
          bottom: TabBar(
            tabs: [
              Tab(text: 'Remote Url'),
              Tab(text: 'Local File'),
              Tab(text: 'Local Asset'),
              Tab(text: 'Notification'),
              Tab(text: 'Advanced'),
            ],
          ),
          title: Text('audioplayers Example'),
        ),
        body: TabBarView(
          children: [remoteUrl(), localFile(), localAsset(), notification(), advanced()],
        ),
      ),
    );
  }
}
导入'dart:async';
导入“dart:io”;
导入“包:AudioPlayer/audio_cache.dart”;
导入“包:AudioPlayer/AudioPlayer.dart”;
进口“包装:颤振/材料.省道”;
导入“包:http/http.dart”;
导入“package:path_provider/path_provider.dart”;
导入“player_widget.dart”;
typedef void OnError(异常);
康斯特库尔https://luan.xyz/files/audio/ambient_c_motion.mp3';
康斯特库尔德酒店https://luan.xyz/files/audio/nasa_on_a_mission.mp3';
常数kUrl3=http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1xtra_mf_p';
void main(){
runApp(新材料应用程序(主页:new ExampleApp());
}
类ExampleApp扩展StatefulWidget{
@凌驾
_ExampleAppState createState()=>新建_ExampleAppState();
}
类\u示例AppState扩展状态{
AudioCache AudioCache=AudioCache();
AudioPlayer advancedPlayer=AudioPlayer();
字符串localFilePath;
Future\u loadFile()异步{
最终字节=等待读取字节(kUrl1);
final dir=等待getApplicationDocumentsDirectory();
最终文件=文件('${dir.path}/audio.mp3');
等待文件。writeAsBytes(字节);
if(wait file.exists()){
设置状态(){
localFilePath=file.path;
});
}
}
小部件_选项卡(列出子项){
返回中心(
子:容器(
填充:所有边缘设置(16.0),
子:列(
children:children.map((w)=>Container(children:w,padding:EdgeInsets.all(6.0))).toList(),
),
),
);
}
小部件_btn(字符串txt,按下VoidCallback){
returnbuttontheme(minWidth:48.0,child:RaisedButton(child:Text(txt),onPressed:onPressed));
}
控件远程URL(){
返回SingleChildScrollView(
子项:_选项卡([
正文(
“样本1($kUrl1)”,
样式:TextStyle(fontWeight:fontWeight.bold),
),
PlayerWidget(url:kUrl1),
正文(
“样本2($kUrl2)”,
样式:TextStyle(fontWeight:fontWeight.bold),
),
PlayerWidget(url:kUrl2),
正文(
“样本3($kUrl3)”,
样式:TextStyle(fontWeight:fontWeight.bold),
),
PlayerWidget(url:kUrl3),
正文(
'示例4(低延迟模式)($kUrl1)',
样式:TextStyle(fontWeight:fontWeight.bold),
),
PlayerWidget(url:kUrl1,模式:PlayerMode.LOW_LATENCY),
]),
);
}
Widget localFile(){
返回选项卡([
Text('File:$kUrl1'),
_btn('Download File to your Device',()=>\u loadFile()),
Text('当前本地文件路径:$localFilePath'),
localFilePath==null?Container():PlayerWidget(url:localFilePath,isLocal:true),
]);
}
Widget localAsset(){
返回选项卡([
文本('Play Local Asset'audio.mp3\':'),
_btn('Play',()=>audioCache.Play('audio.mp3'),
文本('Loop Local Asset'audio.mp3\':'),
_btn('Loop',()=>audioCache.Loop('audio.mp3'),
文本('Play Local Asset'audio2.mp3\':'),
_btn('Play',()=>audioCache.Play('audio2.mp3'),
Text('Play Local Asset In Low Latency'audio.mp3\':'),
_btn('Play',()=>audioCache.Play('audio.mp3',模式:PlayerMode.LOW_LATENCY)),
Text('以低延迟播放本地资源'audio2.mp3\':'),
_btn('Play',()=>audioCache.Play('audio2.mp3',模式:PlayerMode.LOW_LATENCY)),
getLocalFileDuration(),
]);
}
Future\u getDuration()异步{
File audiofile=wait audioCache.load('audio2.mp3');
等待advancedPlayer.setUrl(
audiofile.path,
isLocal:是的,
);
int duration=wait Future.delayed(持续时间(秒数:2),()=>advancedPlayer.getDuration());
返回时间;
}
getLocalFileDuration(){
回归未来建设者(
未来:_getDuration(),
生成器:(BuildContext上下文,异步快照){
交换机(快照.连接状态){
案例连接状态。无:
返回文本('无连接…');
案例连接状态.active:
案例连接状态。正在等待:
返回文本('等待结果…');
案例连接状态。完成:
if(snapshot.hasError)返回文本('Error:${snapshot.Error}');
返回文本('audio2.mp3持续时间为:${duration(毫秒:snapshot.data)});
}
返回null;//不可访问
},
);
}
小部件通知(){
返回选项卡([
Text('播放通知声音:\'messenger.mp3\':'),
_btn('Play',()=>audioCache.Play('messenger.mp3',isNotification:true)),
]);
}
Widget advanced(){
返回选项卡([
栏(儿童:[
文本(“源Url”),
世界其他地区(儿童:[
_btn('Audio 1',()=>advancedPlayer.setUrl(kUrl1)),
_btn('Audio 2',()=>advancedPlayer.setUrl(kUrl2)),
_btn('Stream',()=>advancedPlayer.setUrl(kUrl3)),
],mainAxisAlignment:mainAxisAlignment.space),
]),
栏(儿童:[
文本(“释放模式”),
世界其他地区(儿童:[
_btn('STOP',()=>advancedPlayer.setReleaseMode(ReleaseMode.STOP)),
_btn('LOOP',()=>advancedPlayer.setReleaseMode(ReleaseMode.LOOP)),
_btn('RELEASE',()=>advancedPlayer.setReleaseMode(ReleaseMode.RELEASE)),
],mainAxisAlignment:mainAxisAlignment.space),
]),
新栏目(儿童:[
文本(“卷”),
世界其他地区(儿童:[
_btn('0.0',()=>advancedPlayer.setVolume(0.0)),
_