クロスプラットフォームでローカル画像を3枚表示したいだけなのに、、

Flutter, React Native(Expo), Xamarin.Formsで、振る舞いが同じアプリを作っているんですが、い〜〜〜つっも、ローカール画像を表示する方法を忘れる！！！ :weary:
（だから、ここにメモっとく！）

※iOSとAndroidのバージョン
![iOS-13.3](https://img.shields.io/badge/iOS-13.3-brightgreen)![Android-29(API Level)](https://img.shields.io/badge/Android-29(API Level)-brightgreen)

# フレームワークごとの要点

 - Flutter
    - pubspec.yamlに画像があるフォルダを設定

 - React Native (Expo)
    - requireを配列に格納して、Imageから呼び出す
	    - requireの文字列(ファイルpath)を動的に変更できない！

 - Xamarin.Forms
    - ビルドアクションを「EmbeddedResource」に設定する
    - AndroidとiOSのResource配下に画像のリンクを追加する

# Flutter

![Flutter-1.20.3](https://img.shields.io/badge/Flutter-1.20.3-brightgreen)

1. assetsフォルダの配下に「images」フォルダを新規作成
![スクリーンショット 2021-02-13 15.41.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/34b95df5-4e08-5bb2-2169-32f181be9956.png)
![スクリーンショット 2021-02-13 15.41.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/a4b97c87-59d4-618a-651c-275ba25956fa.png)

2. 新規作成したimagesフォルダをローカル環境で開いて、imagesフォルダに画像を追加
![スクリーンショット 2021-02-13 15.53.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/512c41ee-9f8d-bffd-d270-c1baa68019bf.png)
![スクリーンショット 2021-02-13 15.54.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/b938726f-d2ea-35f1-745d-96b452e99322.png)

3. pubspec.yamlのassetsに上記のフォルダを設定
 - imagesフォルダ配下の画像を全て使う場合は「assets/images/」

```yaml:pubspec.yaml
name: flutterproject
description: A new Flutter application.

version: 1.0.0+1

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^0.1.2

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:

  uses-material-design: true

  assets:
    - assets/images/
```

4.ローカル画像を表示する場合は「Image.asset」を利用

```dart:main.dart
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

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

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {

  List<int> imageCountList = [1, 2, 3];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          children: new List.generate(imageCountList.length, (index){
            return new Image.asset(
              'assets/images/image' + imageCountList[index].toString().padLeft(3, "0") + '.jpg',
              height: 200.0,
              width: 100.0,
            );
          }),
        ),
      ),
    );
  }
}
```

# React Native(Expo)

![React Native cli-2.0.1](https://img.shields.io/badge/React Native cli-2.0.1-brightgreen)![Expo-3.23.3](https://img.shields.io/badge/Expo-3.23.3-brightgreen)

1.assetsフォルダの配下にimagesフォルダを新規作成
![スクリーンショット 2021-02-13 16.16.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/5fcb57f6-380a-135f-3fa2-7e523e9d8dca.png)
![スクリーンショット 2021-02-13 16.17.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/daed398a-3443-939d-c93a-9740e4828d55.png)

2.新規作成したimagesフォルダをローカル環境で開いて、imagesフォルダに画像を追加
![スクリーンショット 2021-02-13 16.19.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/6d3e64f4-cf3d-c879-482e-d7bf11efaf4a.png)
![スクリーンショット 2021-02-13 16.21.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/5b2a3c63-119d-b1bf-3620-66c448c2871c.png)
![スクリーンショット 2021-02-13 16.22.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/1cc72651-1284-36bb-3658-7fc7aebb317c.png)

3.画像pathの文字列をrequireに設定し、key-value形式で定義

4.key-value形式で定義したrequireを配列に格納

5.imageコンポーネントのsourceに、requireが格納された配列のkeyを設定(Keyからrequireを取得)

```javascript:App.js
import React, { Component } from 'react';
import { SafeAreaView, StyleSheet, FlatList, Image } from 'react-native';

export default class App extends Component {

  state = {
    numColumns:3,
    items:[
      {id : "1", req : require('./assets/images/image001.jpg')},
      {id : "2", req : require('./assets/images/image002.jpg')},
      {id : "3", req : require('./assets/images/image003.jpg')},
    ]
  };

  renderItem = ({index}) => {
    return (
      <Image
        style={styles.image}
        source={this.state.items[index].req}
      />
    );
  }

  render() {
    return (
      <SafeAreaView style={styles.container}>
        <FlatList
          data={this.state.items}
          renderItem={this.renderItem}
          keyExtractor={index => index.id}/>
      </SafeAreaView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 100,
    marginLeft: 100,
  },
  itemContainer: {
    justifyContent: 'flex-end',
    borderRadius: 5,
    padding: 10,
    height: 700,
    width: 500,
  },
  image: {
    width: 200,
    height: 100,
    marginLeft: 10,
    marginTop: 10,
  }
});
```

# Xamarin.Forms

![Xamarin.Forms-4.6.0.1141](https://img.shields.io/badge/Xamarin.Forms-4.6.0.1141-brightgreen)

Xamarin.Formsでは、画像を新規に追加する場合と削除してから追加する場合で、少しやり方が異なるので以下にまとめました。

## プロジェクトに新規で画像を追加する場合

1.imagesフォルダを新規追加
![スクリーンショット 2021-02-13 17.12.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/0840af13-405c-bc0d-6366-66626d243ab5.png)
![スクリーンショット 2021-02-13 17.13.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/7daff9b4-95b7-507b-cec2-471a0bb29a15.png)

2.imagesフォルダに画像を追加（ダイアログが出た場合は「ファイルをディレクトリにコピーします」を選択）
![スクリーンショット 2021-02-13 17.14.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/905acd69-82b9-50db-9ab8-655f02cfadc1.png)
![スクリーンショット 2021-02-13 17.14.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/4666ddf3-cd5a-0518-c627-2ea6a43c8525.png)

3.追加した全ての画像を選択して、「右クリック」→「ビルドアクション」→「EmbeddedResource」を選択
![スクリーンショット 2021-02-13 17.15.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/a375eb42-f508-f408-34f0-bc4ef8636b26.png)

4.「プロジェクト名.Android/Resources/layout」を選択して、「右クリック」→「追加」→「既存のフォルダー」を選択
![スクリーンショット 2021-02-13 17.21.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/63d45f8e-d44a-f664-5b3d-9b1a32a87cb5.png)

5.プロジェクト配下にある新規追加したimagesフォルダを選択して「OK」を押下
![スクリーンショット 2021-02-13 17.21.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/fb85d679-2ec1-866a-14c5-1ade63456cee.png)

6.「すべて含める」を押下して、「OK」を押下
![スクリーンショット 2021-02-13 17.21.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/7cb5153f-6b8a-4a37-ef57-47d49afc16f4.png)

7.「ファイルに対するリンクを追加する」を選択し、「OK」を押下
![スクリーンショット 2021-02-13 17.21.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/8d8a3eed-d9b3-31b3-c129-598e5e7baf9c.png)

8.「プロジェクト名.iOS/Resources」を選択して、「右クリック」→「追加」→「既存のフォルダー」を選択
![スクリーンショット 2021-02-13 17.22.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/a03e938b-a025-fea1-fe09-56991562e63b.png)

9.プロジェクト配下にある新規追加したimagesフォルダを選択して「OK」を押下
![スクリーンショット 2021-02-13 17.22.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/b06d6ee8-5105-48ec-990d-4b12bf317613.png)

10.「すべて含める」を押下して、「OK」を押下
![スクリーンショット 2021-02-13 17.22.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/7148f452-0b57-4c0e-237f-352cb39ec056.png)

11.「ファイルに対するリンクを追加する」を選択し、「OK」を押下
![スクリーンショット 2021-02-13 17.22.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/ee6fab6e-9a79-d116-6260-34a577950d0a.png)

12.利用したい画像を選択して、「右クリック」→「プロパティ」を押下
![スクリーンショット 2021-02-13 18.33.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/4113baf5-313c-de77-28db-146e0b7fef60.png)

13.「リソースID」をコピペしておく
(リソースIDは「プロジェクト名.フォルダ名.画像ファイル名.画像ファイルの拡張子」となっている)
![スクリーンショット 2021-02-13 17.15.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/06393d7f-f046-296d-f3d3-d30c1e2fa5e0.png)

14.利用したい画像の枚数分、手順12~手順13を繰り返し

15.XAMLファイルにStackLayoutを追加してx:Name(変数名)を追加

```xml:MainPage.xaml
<?xml version="1.0" encoding="utf-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core" 
    ios:Page.UseSafeArea="true"
    x:Class="xamarin.forms_project.MainPage">
    <StackLayout x:Name="Layout">
    </StackLayout>
</ContentPage>
```

16.コードビハインド(C#)でImageSource.FromResourceに手順14でコピペしたリソースIDを引数に設定

17.コードビハインド(C#)でStackLayoutに付けた変数名に手順16で追加したImageオブジェクトを追加

```C#:MainPage.xaml.cs
using System;
using System.Collections.Generic;
using Xamarin.Forms;

namespace xamarin.forms_project
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            for(int index = 1; index < 4; index++)
            {
                var image = new Image()
                {
                    Source = ImageSource.FromResource("xamarin.forms_project.images.image" + String.Format("{0:D3}", index) + ".jpg"),
                    HorizontalOptions = LayoutOptions.Center,
                    VerticalOptions = LayoutOptions.Center,
                    WidthRequest = 200,
                    HeightRequest = 100,
                };
                Layout.Children.Add(image);
            }
        }
    }
}
```

（ハァ〜〜、疲れた:tired_face:）

## 画像を削除してから再度追加する場合

画像を削除する時は「プロジェクト名/プロジェクト名.csproj」を手動での編集が必要な時があります。

例：プロジェクト名が「xamarin.forms_project」の場合、「xamarin.forms_project/xamarin.forms_project.csproj」を編集する。
![スクリーンショット 2021-02-13 16.51.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/2f37fc7c-2db2-19fe-fae9-e84e85162439.png)

過去に起こったケースでは、VisualStudioからでなく、imagesフォルダやimagesフォルダにある画像ファイルを、ローカルから直接削除して、そのままビルドしてしまった場合に発生しました。こんなエラーでした。

```
重複する 'EmbeddedResource' 個のアイテムが含められました。.NET SDK には、既定でプロジェクト ディレクトリからのアイテムが 'EmbeddedResource' 個含まれています。これらのアイテムをプロジェクト ファイルから削除するか、'EnableDefaultEmbeddedResourceItems' プロパティを 'false' に設定してプロジェクト ファイルに明示的に含めることができます。
```

「プロジェクトに新規で画像を追加する場合」の手順1~手順11で追加した「images」フォルダ、「プロジェクト名.Android」と「プロジェクト名.iOS」にあるimagesフォルダを削除します。その後、「プロジェクト名/プロジェクト名.csproj」をテキストエディタで開き、NoneタグとEmbeddedResourceタグをItemGroupタグごと削除します。そしてVisualStudioで再読み込みします。

before
![スクリーンショット 2021-02-13 16.51.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/ac952888-3ac2-a8ce-2b3b-094adecd8095.png)

after
![スクリーンショット 2021-02-13 16.51.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456945/9c42b743-c98e-2fe9-c825-df09db08b8a4.png)

これらを行なった後で、「プロジェクトに新規で画像を追加する場合」を再度行います。

# 感想
見てもらったらわかりますが、煩雑さは
Flutter < React Native(Expo) < **Xamarin.Forms**
です！
Xamarin.Forms、、:rage::rage: