Xamarin.forms Image实现圆形图片

来源:互联网 发布:小型宝塔数控机床编程 编辑:程序博客网 时间:2024/06/06 04:42

    最近刚使用Xamarin技术开发完一个跨平台APP。怎么说,总的感觉吧,xamarin.forms 坑太多了。记得在最初研究Xamarin.forms技术时,掉进过不少坑。也是啥都不懂。各种刨资料。不得不吐槽下,国内资料真的是少的可怜。没得办法只有翻墙去找资料了。从开始研究这个技术到现在APP上线,大概花了4~5个月。

    也有很多研究xamarin.forms技术的大神们发表着自己不同的意见。只能说仁者见仁智者见智。但是,不得不承认的是,跨平台技术给了我们开发移动端的一个很大的便捷。准确来说,是给C#在移动端世界里开疆扩土的一个很大便捷和机会。自从微软收购Xamarin后,这几年的动静可不小哇。今年发布VS2017的正式版,这给开发人员节省了不少的环境搭配时间。不知道大家有没有体会到使用VS2015开发APP配环境配的连砸电脑的心都有了。接着VS For Mac的出现,这是要逆天的节奏啊,之前在Mac上安装了VS玩了玩,可惜没得中文版的,自我感觉还是没得Windows版的VS好用。毕竟使用Windows版的VS用习惯了。总体来说,使用Xamarin跨平台开发还是很不错的。可以共享UI 和后台代码呀。一套代码可以在Android/iOS/WindowsPhone等不同平台运行。

    今天更大家分享Forms的一个控件Image的相关使用方法。

   我们从Xamrin的官方API可以了解到Image控件就是显示图片的。前面也有很多大神有做专题博客介绍,我这就不做详细介绍了。大致介绍下Image基本常用的属性:   

属性

Aspect

获取或设置图像的缩放模式。这是一个枚举

IsLoading

获取图像的加载状态。(这是一个只读属性)

IsOpaque

获取或设置图像的不透明度标志。

Source

获取或设置图像的源。图片源有很多种,可以来自于文件,图片流,或者URL

·下面来介绍下如何实现圆形图片

      实现圆形图片需要引用到第三方包。

    第一步: 右键你的解决方案选择管理Nuget程序包

在浏览框中搜索   Xlabs.Forms 选中并添加包引用到项目中

 注意  PCL 、Android、iOS 都得添加引用。

在包的下面有此发布的github地址   https://github.com/XLabs/Xamarin-Forms-Labs

点击去对应有控件包如何使用有详细说明。但是其中有个坑。下面我会提到的。

第二步:

 

根据git提到此包使用的文档。我们需要分别在IOS、Android、WindowsPone 上做些小修改

  iOS 修改

  

 如图要将之前的默认继承的基类修改成 XFormsApplicationDelegate

 WindowsPhone 、Android 也是如此做法。但是在Android的中修改会有如下的问题:


  我翻墙在网上找到了对应的解决方法。需要在Android中新建一个类XFormsAppCompatDroid,继承FormsAppCompatActivity

 /// <summary>
    /// Class XFormsAppCompatDroid
    /// </summary>
    public class XFormsAppCompatDroid : FormsAppCompatActivity
    {
        /// <summary>
        /// Gets or sets the destory
        /// </summary>
        /// <value>The destroy.</value>
        public EventHandler<EventArgs> Destroy { get; set; }
        /// <summary>
        /// Gets or sets the pause.
        /// </summary>
        /// <value>The pause.</value>
        public EventHandler<EventArgs> Pause { get; set; }

        /// <summary>
        /// Gets or sets the restart.
        /// </summary>
        /// <value>The restart.</value>
        public EventHandler<EventArgs> Restart { get; set; }

        /// <summary>
        /// Gets or sets the resume.
        /// </summary>
        /// <value>The resume.</value>
        public EventHandler<EventArgs> Resume { get; set; }

        /// <summary>
        /// Gets or sets the start.
        /// </summary>
        /// <value>The start.</value>
        public EventHandler<EventArgs> Start { get; set; }

        /// <summary>
        /// Gets or sets the stop.
        /// </summary>
        /// <value>The stop event handler.</value>
        public EventHandler<EventArgs> Stop { get; set; }

        /// <summary>
        /// Called when [destroy].
        /// </summary>
        protected override void OnDestroy()
        {
            var handler = this.Destroy;
            if (handler != null)
            {
                handler(this, new EventArgs());
            }

            base.OnDestroy();
        }
        
        /// <summary>
        /// Called as part of the activity lifecycle when an activity is going into
        /// the background, but has not (yet) been killed.
        /// </summary>
        /// <since version="Added in API level 1" />
        /// <altmember cref="M:Android.App.Activity.OnResume" />
        /// <altmember cref="M:Android.App.Activity.OnSaveInstanceState(Android.OS.Bundle)" />
        /// <altmember cref="M:Android.App.Activity.OnStop" />
        /// <remarks><para tool="javadoc-to-mdoc">Called as part of the activity lifecycle when an activity is going into
        /// the background, but has not (yet) been killed.  The counterpart to
        /// <c><see cref="M:Android.App.Activity.OnResume" /></c>.
        /// </para>
        /// <para tool="javadoc-to-mdoc">When activity B is launched in front of activity A, this callback will
        /// be invoked on A.  B will not be created until A's <c><see cref="M:Android.App.Activity.OnPause" /></c> returns,
        /// so be sure to not do anything lengthy here.
        /// </para>
        /// <para tool="javadoc-to-mdoc">This callback is mostly used for saving any persistent state the
        /// activity is editing, to present a "edit in place" model to the user and
        /// making sure nothing is lost if there are not enough resources to start
        /// the new activity without first killing this one.  This is also a good
        /// place to do things like stop animations and other things that consume a
        /// noticeable amount of CPU in order to make the switch to the next activity
        /// as fast as possible, or to close resources that are exclusive access
        /// such as the camera.
        /// </para>
        /// <para tool="javadoc-to-mdoc">In situations where the system needs more memory it may kill paused
        /// processes to reclaim resources.  Because of this, you should be sure
        /// that all of your state is saved by the time you return from
        /// this function.  In general <c><see cref="M:Android.App.Activity.OnSaveInstanceState(Android.OS.Bundle)" /></c> is used to save
        /// per-instance state in the activity and this method is used to store
        /// global persistent data (in content providers, files, etc.)
        /// </para>
        /// <para tool="javadoc-to-mdoc">After receiving this call you will usually receive a following call
        /// to <c><see cref="M:Android.App.Activity.OnStop" /></c> (after the next activity has been resumed and
        /// displayed), however in some cases there will be a direct call back to
        /// <c><see cref="M:Android.App.Activity.OnResume" /></c> without going through the stopped state.
        /// </para>
        /// <para tool="javadoc-to-mdoc">
        ///   <i>Derived classes must call through to the super class's
        /// implementation of this method.  If they do not, an exception will be
        /// thrown.</i>
        /// </para>
        /// <para tool="javadoc-to-mdoc">
        ///   <format type="text/html">
        ///     <a href="http://developer.android.com/reference/android/app/Activity.html#onPause()" target="_blank">[Android Documentation]</a>
        ///   </format>
        /// </para></remarks>
        protected override void OnPause()
        {
            var handler = this.Pause;
            if (handler != null)
            {
                handler(this, new EventArgs());
            }

            base.OnPause();
        }

        /// <summary>
        /// Called after <c><see cref="M:Android.App.Activity.OnStop" /></c> when the current activity is being
        /// re-displayed to the user (the user has navigated back to it).
        /// </summary>
        /// <since version="Added in API level 1" />
        /// <altmember cref="M:Android.App.Activity.OnStop" />
        /// <altmember cref="M:Android.App.Activity.OnStart" />
        /// <altmember cref="M:Android.App.Activity.OnResume" />
        /// <remarks><para tool="javadoc-to-mdoc">Called after <c><see cref="M:Android.App.Activity.OnStop" /></c> when the current activity is being
        /// re-displayed to the user (the user has navigated back to it).  It will
        /// be followed by <c><see cref="M:Android.App.Activity.OnStart" /></c> and then <c><see cref="M:Android.App.Activity.OnResume" /></c>.
        /// </para>
        /// <para tool="javadoc-to-mdoc">For activities that are using raw <c><see cref="T:Android.Database.ICursor" /></c> objects (instead of
        /// creating them through
        /// <c><see cref="M:Android.App.Activity.ManagedQuery(Android.Net.Uri, System.String[], System.String[], System.String[], System.String[])" /></c>,
        /// this is usually the place
        /// where the cursor should be required (because you had deactivated it in
        /// <c><see cref="M:Android.App.Activity.OnStop" /></c>.
        /// </para>
        /// <para tool="javadoc-to-mdoc">
        ///   <i>Derived classes must call through to the super class's
        /// implementation of this method.  If they do not, an exception will be
        /// thrown.</i>
        /// </para>
        /// <para tool="javadoc-to-mdoc">
        ///   <format type="text/html">
        ///     <a href="http://developer.android.com/reference/android/app/Activity.html#onRestart()" target="_blank">[Android Documentation]</a>
        ///   </format>
        /// </para></remarks>
        protected override void OnRestart()
        {
            var handler = this.Restart;
            if (handler != null)
            {
                handler(this, new EventArgs());
            }

            base.OnRestart();
        }

        /// <summary>
        /// Called after <c><see cref="M:Android.App.Activity.OnRestoreInstanceState(Android.OS.Bundle)" /></c>, <c><see cref="M:Android.App.Activity.OnRestart" /></c>, or
        /// <c><see cref="M:Android.App.Activity.OnPause" /></c>, for your activity to start interacting with the user.
        /// </summary>
        /// <since version="Added in API level 1" />
        /// <altmember cref="M:Android.App.Activity.OnRestoreInstanceState(Android.OS.Bundle)" />
        /// <altmember cref="M:Android.App.Activity.OnRestart" />
        /// <altmember cref="M:Android.App.Activity.OnPostResume" />
        /// <altmember cref="M:Android.App.Activity.OnPause" />
        /// <remarks><para tool="javadoc-to-mdoc">Called after <c><see cref="M:Android.App.Activity.OnRestoreInstanceState(Android.OS.Bundle)" /></c>, <c><see cref="M:Android.App.Activity.OnRestart" /></c>, or
        /// <c><see cref="M:Android.App.Activity.OnPause" /></c>, for your activity to start interacting with the user.
        /// This is a good place to begin animations, open exclusive-access devices
        /// (such as the camera), etc.
        /// </para>
        /// <para tool="javadoc-to-mdoc">Keep in mind that onResume is not the best indicator that your activity
        /// is visible to the user; a system window such as the key guard may be in
        /// front.  Use <c><see cref="M:Android.App.Activity.OnWindowFocusChanged(System.Boolean)" /></c> to know for certain that your
        /// activity is visible to the user (for example, to resume a game).
        /// </para>
        /// <para tool="javadoc-to-mdoc">
        ///   <i>Derived classes must call through to the super class's
        /// implementation of this method.  If they do not, an exception will be
        /// thrown.</i>
        /// </para>
        /// <para tool="javadoc-to-mdoc">
        ///   <format type="text/html">
        ///     <a href="http://developer.android.com/reference/android/app/Activity.html#onResume()" target="_blank">[Android Documentation]</a>
        ///   </format>
        /// </para></remarks>
        protected override void OnResume()
        {
            var handler = this.Resume;
            if (handler != null)
            {
                handler(this, new EventArgs());
            }

            base.OnResume();
        }

        /// <summary>
        /// Called after <c><see cref="M:Android.App.Activity.OnCreate(Android.OS.Bundle)" /></c> or after <c><see cref="M:Android.App.Activity.OnRestart" /></c> when
        /// the activity had been stopped, but is now again being displayed to the
        /// user.
        /// </summary>
        /// <since version="Added in API level 1" />
        /// <altmember cref="M:Android.App.Activity.OnCreate(Android.OS.Bundle)" />
        /// <altmember cref="M:Android.App.Activity.OnStop" />
        /// <altmember cref="M:Android.App.Activity.OnResume" />
        /// <remarks><para tool="javadoc-to-mdoc">Called after <c><see cref="M:Android.App.Activity.OnCreate(Android.OS.Bundle)" /></c> or after <c><see cref="M:Android.App.Activity.OnRestart" /></c> when
        /// the activity had been stopped, but is now again being displayed to the
        /// user.  It will be followed by <c><see cref="M:Android.App.Activity.OnResume" /></c>.
        /// </para>
        /// <para tool="javadoc-to-mdoc">
        ///   <i>Derived classes must call through to the super class's
        /// implementation of this method.  If they do not, an exception will be
        /// thrown.</i>
        /// </para>
        /// <para tool="javadoc-to-mdoc">
        ///   <format type="text/html">
        ///     <a href="http://developer.android.com/reference/android/app/Activity.html#onStart()" target="_blank">[Android Documentation]</a>
        ///   </format>
        /// </para></remarks>
        protected override void OnStart()
        {
            var handler = this.Start;
            if (handler != null)
            {
                handler(this, new EventArgs());
            }

            base.OnStart();
        }

        /// <summary>
        /// Called when you are no longer visible to the user.
        /// </summary>
        /// <since version="Added in API level 1" />
        /// <altmember cref="M:Android.App.Activity.OnRestart" />
        /// <altmember cref="M:Android.App.Activity.OnResume" />
        /// <altmember cref="M:Android.App.Activity.OnSaveInstanceState(Android.OS.Bundle)" />
        /// <altmember cref="M:Android.App.Activity.OnDestroy" />
        /// <remarks><para tool="javadoc-to-mdoc">Called when you are no longer visible to the user.  You will next
        /// receive either <c><see cref="M:Android.App.Activity.OnRestart" /></c>, <c><see cref="M:Android.App.Activity.OnDestroy" /></c>, or nothing,
        /// depending on later user activity.
        /// </para>
        /// <para tool="javadoc-to-mdoc">Note that this method may never be called, in low memory situations
        /// where the system does not have enough memory to keep your activity's
        /// process running after its <c><see cref="M:Android.App.Activity.OnPause" /></c> method is called.
        /// </para>
        /// <para tool="javadoc-to-mdoc">
        ///   <i>Derived classes must call through to the super class's
        /// implementation of this method.  If they do not, an exception will be
        /// thrown.</i>
        /// </para>
        /// <para tool="javadoc-to-mdoc">
        ///   <format type="text/html">
        ///     <a href="http://developer.android.com/reference/android/app/Activity.html#onStop()" target="_blank">[Android Documentation]</a>
        ///   </format>
        /// </para></remarks>
        protected override void OnStop()
        {
            var handler = this.Stop;
            if (handler != null)
            {
                handler(this, new EventArgs());
            }

            base.OnStop();
        }
    }

    /// <summary>
    /// Class XFormsAppDroid.
    /// </summary>
    public class XFormsAppDroid : XFormsApp<XFormsAppCompatDroid>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="XFormsAppDroid"/> class.
        /// </summary>
        public XFormsAppDroid() { }

        /// <summary>
        /// Initializes a new instance of the <see cref="XFormsAppDroid"/> class.
        /// </summary>
        /// <param name="app">The application.</param>
        public XFormsAppDroid(XFormsAppCompatDroid app) : base(app) { }

        /// <summary>
        /// Raises the back press.
        /// </summary>
        public void RaiseBackPress()
        {
            this.OnBackPress();
        }

        /// <summary>
        /// Called when [initialize].
        /// </summary>
        /// <param name="app">The application.</param>
        /// <param name="initServices">Should initialize services.</param>
        protected override void OnInit(XFormsAppCompatDroid app, bool initServices = true)
        {
            this.AppContext.Start += (o, e) => this.OnStartup();
            this.AppContext.Stop += (o, e) => this.OnClosing();
            this.AppContext.Pause += (o, e) => this.OnSuspended();
            this.AppContext.Resume += (o, e) => this.OnResumed();
            this.AppDataDirectory = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;

            if (initServices)
            {
                DependencyService.Register<TextToSpeechService>();
                DependencyService.Register<Geolocator>();
                DependencyService.Register<MediaPicker>();
                DependencyService.Register<SoundService>();
                DependencyService.Register<EmailService>();
                DependencyService.Register<FileManager>();
                DependencyService.Register<AndroidDevice>();
            }

            base.OnInit(app);
        }
    }

上面是新建的一个类。大家可以直接Copy过去用即可。然后在MainActivity中继承该类即可。

OK  引用此包的大坑问题已经解决。接下来就是使用了。

第三步:使用此第三方自定义控件

我们需要现在Xaml文件中引用

xmlns:controls="clr-namespace:XLabs.Forms.Controls;assembly=XLabs.Forms"
就可以使用此控件进行显示设置圆形图片了。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              xmlns:controls="clr-namespace:XLabs.Forms.Controls;assembly=XLabs.Forms"
             x:Class="ImageSize.ImageDemo">
    <controls:CircleImage Source="index_1.png"
                          WidthRequest="300"
                          HeightRequest="300"
                          Aspect="AspectFill"/>
</ContentPage>


 OK。大功告成。接下来就只用测试调试即可。

 以上是我做的实现圆形图片功能的分享。