解決済み:答えは、すべてのnugetパッケージを更新することでした。 Androidの新しいバージョンをターゲットにします。これで、画像が期待どおりに読み込まれます。 Xamarinが提供するコードを正確に使用していて、新しいバージョンをターゲットにすると、コードが依存するアイテムの一部が非推奨になったため、これには満足していません。初期バージョンはXamarin.Formsv23で、V25に更新しました
画像を表示しようとしているシンプルなビューの新しいXamarinフォームプロジェクトがあります。画像を表示する方法をいくつか試しましたが、まったくうまくいきません。
私は_<image>
_を使用しており、FFImageLoaderコントロールも試しました。
_<StackLayout Orientation="Vertical">
<ff:CachedImage Source="https://static.pexels.com/photos/104827/cat-pet-animal-domestic-104827.jpeg" WidthRequest="100" HeightRequest="100" />
<Button x:Name="btn" Text="Image" Clicked="Button_Clicked" />
<Frame OutlineColor="Red">
<Image x:Name="StupidImage" Source="{Binding Thumbnail}" Aspect="Fill" HeightRequest="100" WidthRequest="100" />
</Frame>
</StackLayout>
_
これが現在のビューです。また、ソースを直接値に設定しましたが、結果はありません。
画像のストリームを取得できます。ストリームからすべてのバイトを読み取ることができます。バイトを画像として表示するデバッグビジュアライザーを作成しました。ソースから画像を取得することは問題ではありません。画像を表示するための画像コントロールを取得することは問題です。
ビューモデルでバインドしてみました。それが失敗したとき、私はそれを直接ソースを設定してみました
_StupidImage.Source = ImageSource.FromStream(() => result.Stream);
_
また、バイトのコピーを作成して試しました
_StupidImage.Source = ImageSource.FromStream(() => new MemoryStream(imageBytes));
_
ImageSource.FromFile()
と_.FromUri
_を試しました。プロジェクトにリソースとして画像を追加してみました。各試行は同じで、リソースが読み取られ、バイトが使用可能でしたが、イメージコントロールはそれを表示しません。
サイズの問題かもしれないと思ったので、コントロールのサイズを設定しました。何もありません。解像度の問題かもしれないと思ったので、小さい画像を使用しました。さまざまな品質のいくつかの異なる画像を試しました。
次に、画像コントロールをあきらめて、FFImageLoading nugetパッケージを取得し、画像への直接URLを指定しました。 FFImageLoadingの例で使用したのと同じ例。まだ画像がありません。
エミュレーターを試し、2つの異なる物理デバイスを試しました。同じ結果。
_btn.Image = "whatever.jpg"
_を使用してボタンに画像を設定してみたところ、同じ結果になりました。
これは毎回の結果です。道に迷いました。画像を表示するにはどうすればよいですか?
編集:これは機能しましたが、エミュレーターでのみ機能しました
_<Image x:Name="StupidImage" Source="https://static.pexels.com/photos/104827/cat-pet-animal-domestic-104827.jpeg" />
_
と同じ
_StupidImage.Source = ImageSource.FromUri(new Uri("https://static.pexels.com/photos/104827/cat-pet-animal-domestic-104827.jpeg"));
_
編集2-明確化
私の目標は、ユーザーがデバイスから写真を選択して、そのプレビューを表示できるようにすることです。
CrossMediaプラグイン の実装を試すことができます。
次に、ボタンをクリックしたコードセクションに、次のように入力します。
Button_Clicked.Clicked += async (sender, args) =>
{
if ( !CrossMedia.Current.IsPickPhotoSupported )
{
DisplayAlert("Error message here", "More message", "OK");
return;
}
var file = await Plugin.Media.CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions
{
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium
});
if (file == null)
return;
image.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
};
ボタンをクリックすると、ギャラリー/ディレクトリが表示されます。あなたが望む写真を選ぶことができます。 OKを押すと、画像が画像コントロール/タグに表示されます。これがあなたが探している解決策であるかどうかはわかりません。それがあなたを正しい方向に導くことを願っています。
リストから削除できるものはいくつかあります。
[x] Visual Studioからの画像の追加:
[x]画像を追加するとき、それは正しい場所にあります:
ProjectName.Driod.Resources.drawable
フォルダ
ProjectName.iOS.Resources
フォルダ
[x]命名規則
。png、すべて小文字、スペースなしまたは両方に特殊文字を使用するのが常に最善ですAndroidとios
iOSを使用すると、通常、次の命名規則で同じ画像の3つの画像を取得します
それらはすべて同じ画像ですが、サイズが異なります
[x] xamlで表示:
<StackLayout>
<Image Source="thedog.png" HeightRequest="100" WidthRequest="100" />
</StackLayout>
Source="{Binding Thumbnail, Mode=TwoWay}"
[〜#〜] nb [〜#〜]これは非常に基本的な説明です
これは、ユーザーが画像を選択してページに表示できるようにする方法です。
画像サービスを呼び出し、コールバックメソッドを渡して画像メソッドを選択します
await _imageService.SelectImage(ImageSelected);
これは私のSelectImageメソッドです。開始時にいくつかの許可チェックがあります。メディアプラグインを使用してギャラリーを表示し、ユーザーが画像を選択できるようにします。
public async Task SelectImage(Action<MediaFile> imageAction)
{
var allowed = await _permissionService.CheckOrRequestStoragePermission();
if (!allowed) return;
if (!_media.IsPickPhotoSupported)
{
throw new GalleryUnavailableException("Gallery unavailable");
}
var file = await _media.PickPhotoAsync(new PickMediaOptions
{
PhotoSize = PhotoSize.Small,
CompressionQuality = 92
});
imageAction(file);
}
MediaFileを返します
これがImageSelectedコールバックメソッドです
private void ImageSelected(MediaFile image)
{
if (image == null)
{
return;
}
ChosenImage = new IncidentImage
{
ImageBytes = image.ToByteArray()
};
}
ChosenImageは私のビューモデルのプロパティです
public IncidentImage ChosenImage {get; set;}
PropertyChanged.Fodyを使用してプロパティ変更通知をトリガーしますが、INotifyPropertyChangedを使用することもできます。
また、IncidentImageは、画像の保存と表示の両方に使用するクラスです。
public class IncidentImage
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public int IncidentDetailsId { get; set; }
public byte[] ImageBytes { get; set; }
[Ignore]
public ImageSource ImageSource
{
get
{
ImageSource retval = null;
try
{
if (ImageBytes != null)
{
retval = ImageSource.FromStream(() => new MemoryStream(ImageBytes));
}
}
catch (Exception e)
{
Debug.WriteLine(e);
}
return retval;
}
}
}
そしてこれがXAMLです
<Image Source="{Binding ChosenImage.ImageSource}"
Aspect="AspectFit"/>
これは、コードを追加するのに役立つ場合とそうでない場合があります。XamarinフォームとAndroidおよびメモリストリームの使用についての驚くべきことの1つは、デバイス密度乗数が引き続き適用されることです。あなたはリソースを使用していないので(私が正しく覚えている場合)、ADBインターフェースを見ていると、メモリの問題が表示されると思います。そのため、画像を表示できません...以前にサンプリングによってこれを解決しました
私がそれを解決した方法は、新しいImageサブクラス-ResourceImageを作成することでした。
public class ResourceImage :Image
{
public enum SourceTypes{
Database,
File,
Function,
}
private bool _LoadAct = false;
public bool LoadAct { get{
return _LoadAct;
}
set{ _LoadAct = value; OnPropertyChanged ("LoadAct");
}
}
public Func<Stream> Func{ get; set; }
public SourceTypes SourceType{ get; set;}
public string ResName{ get; set;}
public ResourceImage ()
{
}
public ResourceImage (string name)
{
ResName = name;
}
public ResourceImage(Func<Stream> func){
SourceType = SourceTypes.Function;
Func = func;
}
}
次にAndroidレンダラー:私は次のことをしました
public class ResourceImageRenderer : ImageRenderer
{
protected override void OnElementChanged (ElementChangedEventArgs<Image> e)
{
base.OnElementChanged (e);
if (e.OldElement == null)
{
var el = (ResourceImage)Element;
if (el.SourceType == ResourceImage.SourceTypes.Database) {
//Ignore for now
} else if (el.SourceType == ResourceImage.SourceTypes.File) {
using (global::Android.Graphics.BitmapFactory.Options options = new global::Android.Graphics.BitmapFactory.Options ()) {
options.InJustDecodeBounds = false;
options.InSampleSize = 1;//calculateInSampleSize (options, outS.X / 4, outS.Y / 4);
var Gd = Context.Resources.GetIdentifier (el.ResName.Split (new char[]{ '.' }) [0], "drawable", Context.PackageName);
using (global::Android.Graphics.Rect rt = new global::Android.Graphics.Rect (0, 0, 0, 0)) {
var bitmap = global::Android.Graphics.BitmapFactory.DecodeResource (Context.Resources, Gd, options);//DecodeStream (ms, rt, options);
bitmap.Density = global::Android.Graphics.Bitmap.DensityNone;
Control.SetImageDrawable (new global::Android.Graphics.Drawables.BitmapDrawable (bitmap));
}
}
} else if (el.SourceType == ResourceImage.SourceTypes.Function) {
new Task (() => {
var ms = el.Func();
if(ms == null)return;
global::Android.Graphics.BitmapFactory.Options options = new global::Android.Graphics.BitmapFactory.Options ();
options.InJustDecodeBounds = false;
options.InSampleSize = 2;//calculateInSampleSize (options, outS.X / 4, outS.Y / 4);
ms.Position = 0;
Device.BeginInvokeOnMainThread(()=>{
using (global::Android.Graphics.Rect rt = new global::Android.Graphics.Rect (0, 0, 0, 0)) {
try{
var bitmap = global::Android.Graphics.BitmapFactory.DecodeStream (ms, rt, options);
bitmap.Density = global::Android.Graphics.Bitmap.DensityNone;
Control.SetImageDrawable (new global::Android.Graphics.Drawables.BitmapDrawable (bitmap));
}catch(Exception eee){
}
}
});
}).Start();
}
}
}
コードを振り返ると(何年も触れていません)、改善の余地はたくさんあります。同じ問題を解決するためにサンプリングを追加する必要がありました。ユーザーはメッセージングアプリに表示する画像を選択していましたが、完全に機能しました。 iOSがAndroidに表示されることはありません