😜

SharedPreferenceを使い画像(path)をアプリ側に保存する

9 min read

※注意点

ImagePickerの導入は済んでいることを前提にしています。

目次

1.SharedPreferenceの導入
2.最小限のUIを作成。
3.画像を取得する処理(メソッド)を作成・表示。
4.画像(path)を保存するボタンと処理の作成。
5.アプリ起動時に画像が設定されているようにする。
(完成)
6.最後に

1.SharedPreferenceの導入

https://pub.dev/packages/shared_preferences

1.1 pubspec.yamlファイルに以下の文を記入

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  image_picker: ^0.8.4+4
  shared_preferences: ^2.0.9   //この文を追加(バージョンっは、最新の物を使用してください)

記入後 pubgetしましょう。

2.最小限のUIを作成。

main.dart
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  File? imageFile;
  String? message = '画像';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('タイトル'),
      ),
      body: Container(
        width: double.infinity,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            Container(
                decoration: BoxDecoration(border: Border.all()),
                height: 200,
                width: 200,
                child: imageFile != null
                    ? Image.file(imageFile!)
                    : Center(
                        child: Text(
                        message!,
                        style: TextStyle(fontSize: 30),
                      ))),
            ElevatedButton(
                onPressed: () async {},
                child: Text(
                  '端末の画像を取ってくる',
                  style: TextStyle(fontSize: 24),
                )),
            ElevatedButton(
                onPressed: () async {},
                child: Text(
                  '端末に画像を保存',
                  style: TextStyle(fontSize: 24),
                )),
          ],
        ),
      ),
    );
  }
}

3.画像を取得する処理(メソッド)を作成・表示。

画像を取得する処理(メソッド)を作成

main.dart
  Future<void> getImage() async {
    final ImagePicker picker = ImagePicker();
    final pickerFile = await picker.pickImage(source: ImageSource.gallery);
    if (pickerFile != null) {
      imageFile = File(pickerFile.path);
    } else {
      message = '画像取得に失敗しました。';
    }
  }

imageFileとmessageは_MyHomePageStateクラスの変数で定義しています。

main.dart
class _MyHomePageState extends State<MyHomePage> {
  File? imageFile;
  String? message = '画像';

"端末の画像を取ってくる"ボタンを押した時に、メソッドを呼び出し、setStateで更新する。

main.dart
ElevatedButton(
                onPressed: () async{
                  await getImage();   //ここを追加
                  setState(() {});    //ここを追加
                },
                child: Text(
                  '端末の画像を取ってくる',
                  style: TextStyle(fontSize: 24),
                )),

4.画像(path)を保存するボタンと処理の作成。

画像の(path)を保存する処理(メソッド)を作成

main.dart
 Future<void> saveImagePath() async {
    if(imageFile != null) {
      final SharedPreferences prefs = await SharedPreferences.getInstance();
    isSaveImage = await prefs.setString('imagePath', imageFile!.path);
   setState(() {});
    }
  }

isSaveImageにはちゃんと保存できたかのbool型が入ります。

"端末に画像を保存"ボタンを押した時に、メソッドを呼び出し、setStateで更新する。

main.dart
ElevatedButton(
                onPressed: () async {
                  await saveImagePath();
                  setState(() {});
                },
                child: Text(
                  '端末に画像を保存',
                  style: TextStyle(fontSize: 24),
                )),

5.アプリ起動時に画像が設定されているようにする。

ちゃんとSharedPreferenceでアプリ側に、画像pathが保存されているか確認していきましょう。
まず、SharePreferenceを使用するメソッドが、画像pathを保存する時と、画像pathを取ってくるところで、共通で使用したいので、外に出します。

main.dart
以下を追加
Future<void> getSharedPreference() async{
    prefs = await SharedPreferences.getInstance();
  }

SharedPreferences.getInstance()をメソッド化したことで、保存する処理(saveImagePath)内のかぶっている処理が必要なくなったので、削除する。

main.dart
 Future<void> saveImagePath() async {
    if(imageFile != null) {
    
     //この行を削除 final SharedPreferences prefs = await SharedPreferences.getInstance();   //この行を削除
     isSaveImage = await prefs.setString('imagePath', imageFile!.path);
    }
  }

起動した時に、SharedPreferenceのインスタンス内に、保存した"imagePath"があるなら、
それを画像として、表示するというメソッドを作る。

main.dart
Future<void> setImage() async {
    final String? imagePath = prefs.getString('imagePath');
    if (imagePath != null) {
      imageFile = File(imagePath);
      setState(() {});
    }
  }

画面が描画される時に、メソッドを呼び出す。

main.dart
class _MyHomePageState extends State<MyHomePage> {
  File? imageFile;
  String? message = '画像';
  bool saveFinish = false;

  late SharedPreferences prefs;

  @override
  Widget build(BuildContext context) {
    Future.value(setImage());    //ここを追加

    return Scaffold(
      appBar: AppBar(
        title: Text('タイトル'),
      ),
      body: Container(
        width: double.infinity,
        child: Column(

Futureメソッドなので、Future.valueで包みました。実際は必要ないかも

この時点で、端末のアプリを一度デリートし、再クリエイトしたほうがうまくいきます。

以上で画像pathの保存と、pathを使ったImageFileの設置は完了です。

最後に

全文を載せておきます。

main.dart
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  File? imageFile;
  String? message = '画像';
  bool isSaveFinish = false;

  late SharedPreferences prefs;

  @override
  Widget build(BuildContext context) {
    Future.value(setImage());

    return Scaffold(
      appBar: AppBar(
        title: Text('タイトル'),
      ),
      body: Container(
        width: double.infinity,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            Container(
                decoration: BoxDecoration(border: Border.all()),
                height: 200,
                width: 200,
                child: imageFile != null
                    ? Image.file(imageFile!)
                    : Center(
                        child: Text(
                        message!,
                        style: TextStyle(fontSize: 30),
                      ))),
            ElevatedButton(
                onPressed: () async {
                  await getImage();
                  setState(() {});
                },
                child: Text(
                  '端末の画像を取ってくる',
                  style: TextStyle(fontSize: 24),
                )),
            ElevatedButton(
                onPressed: () async {
                  await saveImagePath();
                  setState(() {});
                },
                child: Text(
                  '端末に画像を保存',
                  style: TextStyle(fontSize: 24),
                )),
            if (isSaveFinish)
              Text(
                '保存できました。',
                style: TextStyle(fontSize: 24),
              ),
          ],
        ),
      ),
    );
  }

  Future<void> getImage() async {
    final ImagePicker picker = ImagePicker();
    final pickerFile = await picker.pickImage(source: ImageSource.gallery);
    if (pickerFile != null) {
      imageFile = File(pickerFile.path);
    } else {
      message = '画像取得に失敗しました。';
    }
  }

  Future<void> saveImagePath() async {
    if (imageFile != null) {
      isSaveFinish = await prefs.setString('imagePath', imageFile!.path);
      setState(() {});
    }
  }

  Future<void> getSharedPreference() async {
    prefs = await SharedPreferences.getInstance();
  }

  Future<void> setImage() async {
    await getSharedPreference();
    final String? imagePath = prefs.getString('imagePath');
    if (imagePath != null) {
      imageFile = File(imagePath);
      setState(() {});
    }
  }
}

Discussion

ログインするとコメントできます