続き。

PDFの閲覧をページ単位のスワイプにできますか?
scrollDirection: Axis.horizontal で横スクロール
pageSnap: true により1ページずつのスワイプ切り替えが有効
変更してみるけど、ビルドエラー。
lib/main.dart:130:9: Error: No named parameter with the name 'pageSnap'.
pageSnap: true,
^^^^^^^^
../../.pub-cache/hosted/pub.dev/pdfx-2.6.0/lib/src/viewer/simple/pdf_view.dart:20:9: Context: Found this candidate, but the arguments don't match.
const PdfView({
^^^^^^^
Target kernel_snapshot_program failed: Exception
pdfx 2.6.0 の PdfView ウィジェットには pageSnap パラメータは存在しません。これは PageView のプロパティであり、PdfView では内部実装に依存しているため、直接使えません。
body: PdfView(
controller: _pdfController,
scrollDirection: Axis.horizontal,
),
これだけで ページ単位のスワイプ は基本的に有効です(各ページが画面全体に表示される仕様)。明示的にスナップ動作を設定する必要はありません。
いや、おまえだろ... コード出せっていったら、だいぶ後退したコード出してきた。
めんどくさいので手動で修正する。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('PDFビューア')),
body: PdfViewPinch(
controller: _pdfController,
scrollDirection: Axis.horizontal,
),
);
}
ビルド通ったアプリは、必要条件は満たしている感じ。
PDFの表示位置もよくないかな。これは、まぁいいか。

PDF表示画面の「PDFビューア」はよくないので、「メニューに戻る」にする。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('メニューに戻る')),
body: PdfViewPinch(
controller: _pdfController,
scrollDirection: Axis.horizontal,
),
);
}
7インチのタブレットで表示してみると、メニューの画像が小さくして黒枠出てしまう。これはあかんね。
あとPDFの起動が遅くてタイムラグがある。データが大きいからしょうがないところあるけど。スクロールもイマイチでスムース感がない。うーん。


メニュー画像を端末画面の横幅いっぱいに拡大したい場合は、Image.asset() の fit を BoxFit.fitWidth にし、縦方向にスクロールが発生しないように SingleChildScrollView などを使わずに Center の代わりに SizedBox.expand や Align を使うのが簡潔です。
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: openBook,
onHorizontalDragEnd: _onSwipe,
child: Scaffold(
body: SizedBox.expand(
child: Image.asset(
books[currentIndex].imagePath,
fit: BoxFit.fitWidth,
alignment: Alignment.center,
),
),
),
);
}
まぁ、これでいいんじゃない。5秒でメニューの表紙は切り替わるし、スワイプで次の候補にスクロールもできる。

ターゲットの10インチNexus10に入れてみる。古すぎでマシンスペック低すぎなので、遅いかな...
しかし、そこまで遅い感じもない。PDFの展開時間はサイズ依存だな。7インチと違って想定通りPDF画面は全画面に近くなる。面倒なので、7インチ向けの調整はしない。
pdfxでページごとのスクロールを行うことができますか?
PdfView(
controller: _pdfController,
scrollDirection: Axis.horizontal, // または Axis.vertical
)
修正を手パッチする。なんか、PDFのレンダリングも早くなった感じ。ロードも軽い。ページ単位だからかな?
いまんとこ、こんなコード。
import 'package:flutter/material.dart';
import 'package:pdfx/pdfx.dart';
import 'dart:async';
void main() => runApp(BookPreviewApp());
class BookPreviewApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '電子書籍プレビュー',
theme: ThemeData.dark(),
home: BookMenuPage(),
);
}
}
class BookMenuPage extends StatefulWidget {
@override
_BookMenuPageState createState() => _BookMenuPageState();
}
class _BookMenuPageState extends State<BookMenuPage> {
final List<BookItem> books = [
BookItem('assets/sample1_thumb.jpg', 'assets/sample1.pdf'),
BookItem('assets/sample2_thumb.jpg', 'assets/sample2.pdf'),
BookItem('assets/sample3_thumb.jpg', 'assets/sample3.pdf'),
];
int currentIndex = 0;
Timer? _slideshowTimer;
@override
void initState() {
super.initState();
_startSlideshow();
}
void _startSlideshow() {
_slideshowTimer = Timer.periodic(Duration(seconds: 5), (timer) {
setState(() {
currentIndex = (currentIndex + 1) % books.length;
});
});
}
@override
void dispose() {
_slideshowTimer?.cancel();
super.dispose();
}
void _onSwipe(DragEndDetails details) {
if (details.primaryVelocity == null) return;
setState(() {
if (details.primaryVelocity! < 0) {
currentIndex = (currentIndex + 1) % books.length;
} else if (details.primaryVelocity! > 0) {
currentIndex = (currentIndex - 1 + books.length) % books.length;
}
});
}
void openBook() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
PDFViewPage(pdfPath: books[currentIndex].pdfPath),
),
);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: openBook,
onHorizontalDragEnd: _onSwipe,
child: Scaffold(
body: SizedBox.expand(
child: Image.asset(
books[currentIndex].imagePath,
fit: BoxFit.fitWidth,
alignment: Alignment.center,
),
),
),
);
}
}
class BookItem {
final String imagePath;
final String pdfPath;
BookItem(this.imagePath, this.pdfPath);
}
class PDFViewPage extends StatefulWidget {
final String pdfPath;
PDFViewPage({required this.pdfPath});
@override
_PDFViewPageState createState() => _PDFViewPageState();
}
class _PDFViewPageState extends State<PDFViewPage> {
late PdfController _pdfController;
@override
void initState() {
super.initState();
_pdfController = PdfController(
document: PdfDocument.openAsset(widget.pdfPath),
);
}
@override
void dispose() {
_pdfController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('メニューに戻る')),
body: PdfView(
controller: _pdfController,
scrollDirection: Axis.horizontal,
),
);
}
}
使ってみると、スクロールするにはページの半分以上の距離をドラッグする必要がある。ちょっとつらい。スクロールも残しつつ、左右タップでのページ送りに変更したい。
PdfView を Stack に包み、左右半分に透明な GestureDetector を重ねます:
return Scaffold(
appBar: AppBar(title: Text('メニューに戻る')),
body: Stack(
children: [
PdfView(
controller: _pdfController,
scrollDirection: Axis.horizontal,
),
Row(
children: [
// 左半分
Expanded(
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () async {
final page = await _pdfController.page;
_pdfController.goToPage(page - 1);
},
),
),
// 右半分
Expanded(
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () async {
final page = await _pdfController.page;
_pdfController.goToPage(page + 1);
},
),
),
],
),
],
),
);
変更を反映してビルドするとエラーになる。
lib/main.dart:143:36: Error: The method 'goToPage' isn't defined for the class 'PdfController'.
- 'PdfController' is from 'package:pdfx/src/viewer/simple/pdf_view.dart' ('../../.pub-cache/hosted/pub.dev/pdfx-2.6.0/lib/src/viewer/simple/pdf_view.dart').
Try correcting the name to the name of an existing method, or defining a method named 'goToPage'.
_pdfController.goToPage(page - 1);
^^^^^^^^
lib/main.dart:153:36: Error: The method 'goToPage' isn't defined for the class 'PdfController'.
- 'PdfController' is from 'package:pdfx/src/viewer/simple/pdf_view.dart' ('../../.pub-cache/hosted/pub.dev/pdfx-2.6.0/lib/src/viewer/simple/pdf_view.dart').
Try correcting the name to the name of an existing method, or defining a method named 'goToPage'.
_pdfController.goToPage(page + 1);
^^^^^^^^
Target kernel_snapshot_program failed: Exception
pdfx 2.6.0 の PdfController には goToPage() は存在せず、代わりに jumpToPage() を使用します。
またかよ... おめーだろ!
修正してビルドする。
左右タップでページめくりできている。スワイプも有効。
なんか、悪くないね。新しいページをロードするときにはNexus10では少しだけブラックアウトするけど、これはそんなもんだね。背景白にするとチラチラはおさえられるかな?
一度表示してキャッシュしたページはすぐに表示される。
pdfx の PdfView は、新しいページを読み込む際に一瞬背景が黒になる仕様があります。これは PdfView が内部でページの読み込み中にデフォルトの背景色(黒)を表示しているためです。
PdfView(
controller: _pdfController,
scrollDirection: Axis.horizontal,
backgroundDecoration: BoxDecoration(
color: Colors.white, // ← 背景を白に変更
),
),
Clineとかなら勝手にやってくれるのかな。手パッチする。ChatGPTはアホなので、セッションが長くなると、前のコードへの変更を出せないことがあったり、変なコードを勝手に入れてきたりするのが面倒ね。
ビルドする。背景、白くならねー。
pdfx の PdfView において、backgroundDecoration が効かないのは仕様上の制限です。特に Android で PdfRenderer を使用している場合、描画時のページ背景色はネイティブレイヤーで黒に固定されている ため、Flutter側から BoxDecoration(color: ...) で背景色を変更しても影響を与えられません。
Flutter 側から pdfx の描画背景を白にすることは現状 不可能に近く、ネイティブ側のコード修正が必要です。
おまえな...
まぁ、これでいいか。アイコン変更したり、署名したりも面倒なのでしない。とりあえず、メニューの画像にはQRを入れた。画面遷移したら同じ絵だとモードが変わったことに気が付かないから。
リリースビルドする。
% flutter build apk --release
% flutter install --release
データを増やすには、assetsにデータを入れて、pubspec.yamlにファイルパス追記して、main.dartに追記する。
final List<BookItem> books = [
BookItem('assets/sample1_thumb.jpg', 'assets/sample1.pdf'),
BookItem('assets/sample2_thumb.jpg', 'assets/sample2.pdf'),
BookItem('assets/sample3_thumb.jpg', 'assets/sample3.pdf'),
BookItem('assets/sample4_thumb.jpg', 'assets/sample4.pdf'), // ← 追加
];
ビルドする前に以下を実行する。
% flutter pub get
あと、機能追加するとしたら、PDF表示て一定時間が経過したら、メニューに戻るみたいのかな。面倒だからしないけど。あとは、ファイルをアプリ埋め込みにしているけど、これを外部フォルダ参照にするかどうか。それも面倒だな。
試読用のアプリ(展示向け) - YouTube
https://www.youtube.com/watch?v=4l1IUJ0JQdA
オリジナル投稿:
FlutterでPDFビュアー作る -2-|kinneko|pixivFANBOX
https://kinneko.fanbox.cc/posts/9758876



