Skip to content

Commit

Permalink
feat: listview like weibo (#149)
Browse files Browse the repository at this point in the history
* fix: fijkValue hash value missing videoRenderStart audioRenderStart
* feat: add cover imageProvider for FijkView
* fix: check mounted before setState, check null player
  • Loading branch information
befovy authored Dec 23, 2019
1 parent 2889371 commit d6a40ca
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 178 deletions.
3 changes: 3 additions & 0 deletions example/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
.history
.svn/

# Flutter
.flutter-plugins-dependencies

# IntelliJ related
*.iml
*.ipr
Expand Down
Binary file added example/assets/cover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
194 changes: 141 additions & 53 deletions example/lib/listview.dart
Original file line number Diff line number Diff line change
@@ -1,77 +1,165 @@
import 'dart:async';

import 'package:fijkplayer/fijkplayer.dart';
import 'package:fijkplayer_example/my_sliver_child_builder_delegate.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

import 'app_bar.dart';

class ListScreen extends StatefulWidget {
class ListItemPlayer extends StatefulWidget {
final int index;
final ValueNotifier<double> notifier;

ListItemPlayer({@required this.index, @required this.notifier});

@override
_ListScreenState createState() => _ListScreenState();
_ListItemPlayerState createState() => _ListItemPlayerState();
}

class _ListScreenState extends State<ListScreen> {
static int listItemCount = 15;
final Map<int, FijkPlayer> _players = Map();
class _ListItemPlayerState extends State<ListItemPlayer> {
FijkPlayer _player;
Timer _timer;
bool _start = false;
bool _expectStart = false;

@override
void initState() {
super.initState();
widget.notifier.addListener(scrollListener);
int mills = widget.index <= 3 ? 100 : 500;
_timer = Timer(Duration(milliseconds: mills), () async {
_player = FijkPlayer();
await _player?.setDataSource("asset:///assets/butterfly.mp4");
await _player?.prepareAsync();
scrollListener();
if (mounted) {
setState(() {});
}
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: FijkAppBar.defaultSetting(title: "List View"),
body: ListView.custom(
childrenDelegate: MySliverChildBuilderDelegate(
(BuildContext context, int index) {
if (!_players.containsKey(index)) {
_players[index] = FijkPlayer();
_players[index].setDataSource("asset:///assets/butterfly.mp4");
}
FijkLog.i("build list item $index", tag: "list");
return Column(
children: <Widget>[
Container(
height: 240.0,
child: FijkView(
player: _players[index],
),
),
SizedBox(height: 12.0)
],
);
},
childCount: listItemCount,
onItemVisibilityState: setVideoVisibilityState,
),
//设置cacheExtent 为0.0 不然获取到的显示隐藏的index不准确
cacheExtent: 0.0,
),
);
}
void scrollListener() {
if (!mounted) return;

void setVideoVisibilityState(List<int> exposure, List<int> hidden) {
exposure.forEach((index) {
//显示的indexs
if (_players[index]?.state == FijkState.idle) {
_players[index]?.setDataSource("asset:///assets/butterfly.mp4");
/// !!important
/// If items in your list view have different height,
/// You can't get the first visible item index by
/// dividing a constant height simply
double pixels = widget.notifier.value;
int x = (pixels / 200).ceil();
if (_player != null && widget.index == x) {
_expectStart = true;
_player.removeListener(pauseListener);
if (_start == false && _player.isPlayable()) {
FijkLog.i("start from scroll listener $_player");
_player.start();
_start = true;
} else if (_start == false) {
FijkLog.i("add start listener $_player");
_player.addListener(startListener);
}
});
hidden.forEach((index) async {
//隐藏的indexs
_players[index]?.stop();
_players[index]?.reset();
});
} else if (_player != null) {
_expectStart = false;
_player.removeListener(startListener);
if (_player.isPlayable() && _start) {
FijkLog.i("pause from scroll listener $_player");
_player.pause();
_start = false;
} else if (_start) {
FijkLog.i("add pause listener $_player");
_player.addListener(pauseListener);
}
}
}

void startListener() {
FijkValue value = _player.value;
if (value.prepared && !_start && _expectStart) {
_start = true;
FijkLog.i("start from player listener $_player");
_player.start();
}
}

void pauseListener() {
FijkValue value = _player.value;
if (value.prepared && _start && !_expectStart) {
_start = false;
FijkLog.i("pause from player listener $_player");
_player?.pause();
}
}

void finalizer() {
_player?.removeListener(startListener);
_player?.removeListener(pauseListener);
var player = _player;
_player = null;
player?.release();
}

@override
void dispose() {
super.dispose();
_players.forEach((i, p) {
p.release();
});
_players.clear();
widget.notifier.removeListener(scrollListener);
_timer?.cancel();
finalizer();
}

@override
Widget build(BuildContext context) {
FijkFit fit = FijkFit(
sizeFactor: 1.0,
aspectRatio: 480 / 270,
alignment: Alignment.center,
);
return Container(
height: 200,
child: Column(
children: <Widget>[
Text("${widget.index}", style: TextStyle(fontSize: 20)),
Expanded(
child: _player != null
? FijkView(
player: _player,
fit: fit,
cover: AssetImage("assets/cover.png"),
)
: Container(
width: double.infinity,
decoration: BoxDecoration(color: const Color(0xFF607D8B)),
child: Image.asset("assets/cover.png"),
),
)
],
));
}
}

class ListScreen extends StatefulWidget {
@override
_ListScreenState createState() => _ListScreenState();
}

class _ListScreenState extends State<ListScreen> {
final ValueNotifier<double> notifier = ValueNotifier(-1);

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: FijkAppBar.defaultSetting(title: "List View"),
body: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
notifier.value = notification.metrics.pixels;
return true;
},
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ListItemPlayer(index: index, notifier: notifier);
},
cacheExtent: 1,
),
));
}
}
110 changes: 0 additions & 110 deletions example/lib/my_sliver_child_builder_delegate.dart

This file was deleted.

1 change: 1 addition & 0 deletions example/lib/recent_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const List<MediaUrl> samples = [
MediaUrl(
title: "http 404", url: "https://fijkplayer.befovy.com/butterfly.flv"),
MediaUrl(title: "assets file", url: "asset:///assets/butterfly.mp4"),
MediaUrl(title: "assets file", url: "asset:///assets/birthday.mp4"),
MediaUrl(title: "assets file 404", url: "asset:///assets/beebee.mp4"),
MediaUrl(
title: "Protocol not found", url: "noprotocol://assets/butterfly.mp4"),
Expand Down
1 change: 1 addition & 0 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ flutter:
# To add assets to your application, add an assets section, like this:
assets:
- assets/butterfly.mp4
- assets/cover.png
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg

Expand Down
15 changes: 13 additions & 2 deletions lib/core/fijkvalue.dart
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,19 @@ class FijkValue {
hashCode == other.hashCode;

@override
int get hashCode => hashValues(prepared, completed, state, size, rotate,
duration, fullScreen, exception, opaque);
int get hashCode => hashValues(
prepared,
completed,
state,
size,
rotate,
videoRenderStart,
audioRenderStart,
duration,
fullScreen,
exception,
opaque,
);

@override
String toString() {
Expand Down
Loading

0 comments on commit d6a40ca

Please sign in to comment.