首页 文章

使用Xamarin Forms显示图像

提问于
浏览
5

Solved: 答案是更新所有nuget软件包并定位更新版本的Android . 现在图像按预期加载 . 我对此并不满意,因为我正在使用Xamarin提供的代码,并且针对较新版本已经弃用了代码所依赖的一些项目 . 初始版本是Xamarin.Forms v23,我更新到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>

这是当前的观点 . 我还将Source直接设置为没有结果的值 .

我能够获得图像的流 . 我能够从流中读取所有字节 . 我构建了一个调试可视化工具,将字节显示为图像 . 从源获取图像不是问题 . 获取图像控件以显示图像是一个问题 .

我尝试用视图模型绑定 . 当失败时,我尝试直接设置源

StupidImage.Source = ImageSource.FromStream(() => result.Stream);

我也做了一个字节的副本并尝试过

StupidImage.Source = ImageSource.FromStream(() => new MemoryStream(imageBytes));

我试过 ImageSource.FromFile().FromUri . 我尝试将图像作为资源添加到项目中 . 每次尝试都是相同的,资源被读取并且字节可用,但图像控件只是不显示它 .

我想也许这是一个尺寸问题,所以我设置了控件的大小 . 没有 . 我想也许这是一个分辨率问题,所以我使用了一个较小的图像 . 我尝试了几种不同质量的不同图像 .

然后我放弃了图像控制,我得到了FFImageLoading nuget包,并给了它一个直接的URL到图像 . FFImageLoading示例使用的相同示例 . 仍然没有形象 .

我尝试了模拟器,我尝试了两种不同的物理设备 . 结果相同 .

我也尝试使用 btn.Image = "whatever.jpg" 在按钮上设置图像,结果相同 .

这是每次的结果 . 我迷路了 . 如何显示图像?

EDIT: 我确实让这个工作,但只在模拟器上

<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"));

EDIT 2 - Clarification

我的目标是允许用户从设备中选择一张照片,然后显示它的预览 .

enter image description here

5 回答

  • 0

    如果您想在应用程序中使用图像,可以将它们加载到共享项目中,例如

    Embedded resource

    确保将 Build Action 更改为 Embedded resource

    然后在你的代码中

    image.Source = ImageSource.FromResource("App5.Images.useravatar.png");
    

    请注意资源名称 .

    和XAML

    <ContentPage.Content>
        <StackLayout>
            <Image x:Name="image" WidthRequest="50"/>
        </StackLayout>
    </ContentPage.Content>
    
  • 1

    您可以从列表中删除一些内容:

    [x]从Visual studio添加图像:

    • 右键单击正确的文件夹

    • 选择添加>>新文件...注意:您必须使用visual studio添加它,而不是将其放入文件夹中 . Visual Studio需要了解它

    [x]添加图像时,它位于正确的位置:

    • 对于android:它必须在

    ProjectName.Driod.Resources.drawable 文件夹

    • 对于ios:它必须在

    ProjectName.iOS.Resources 文件夹

    [x]命名公约

    • 总是最好在android和ios上使用 .pngall lowercaseno spaces 或特殊字符

    • 与ios通常使用以下namting约定获得相同图像的3张图像

    • theman.png

    • theman@2x.png

    • theman@3x.png

    • 它们都是不同尺寸的相同图像

    [x]以xaml显示:

    <StackLayout>
         <Image Source="thedog.png" HeightRequest="100" WidthRequest="100" />
       </StackLayout>
    
    • 在你的例子中你使用了一个框架,stacklayout怎么样?框架有更多要求 .

    • 对于MVVM,您可以使用以下内容更改Source,不要忘记twoway :)

    • Source="{Binding Thumbnail, Mode=TwoWay}"

    NB 这是非常基本的解释

  • 4

    您可以尝试实现CrossMedia Plugin .

    然后在按钮单击代码部分中,输入以下内容:

    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;
                });
            };
    

    单击按钮后,将显示gallery /目录 . 您可以选择所需的照片 . 点击OK后,图像将显示在图像控件/标签中 . 我不确定这是否是您正在寻找的解决方案 . 希望它能帮助你找到正确的方向 .

  • 0

    这可能会或可能不会帮助我添加一些代码,关于Xamarin表单和Android以及使用内存流的令人惊讶的事情之一..即使您没有使用资源,设备密度乘数仍然应用(如果我正确记得)所以我想如果你正在看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上显示过

  • 1

    这是我允许用户选择图像然后在页面上显示的方式 .

    我调用我的图像服务选择Image方法传递一个回调方法

    await _imageService.SelectImage(ImageSelected);
    

    这是我的SelectImage方法 . 一开始就有一些权限检查 . 它使用Media Plugin显示图库并允许用户选择图像 .

    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

    这是Image Selected回调方法

    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"/>
    

相关问题