記事一覧

ListViewの画像を丸型に表示する方法 | Xamarin.Forms


今回は、よくあるListViewで画像(Image)を丸型に表示する方法をご紹介いたします。描画に関するテクニックですので、基本的にはカスタムレンダラーで記述することが想定できます。しかしながら、Xamarinの公式ブログページで表示方法について書かれており、GitHubにもImageCircleのソースコードがあり、どちらも実際に試してみたところ、iOSでは正しく動作しましたが、Androidでは正しく表示できませんでした(※初回表示のみ表示できましたが、2回目の表示以降は画像が正しく表示できませんでした。)ので、ここに正しく表示できるソースコードをご紹介いたします。


Android5
xamarin_listview_image_01.jpg
iOS9
xamarin_listview_image_02.jpg


前提条件
・Windows10 Pro 64Bit
・Visual Studio 2015 Community Update3
・Xamarin 4.3.0.784 (NuGet Xamarin.Forms 2.3.4.224)
・macOS Sierra 10.12.4 / Xcode8.3.1 / Xamarin.iOS 10.4.0.123


1.Androidでの実装方法

Xamarinの公式ブログページではDrawChildをオーバーライドして画像を丸型に編集する方法が紹介されていましたが、実際に実装してみると丸型にはなっていましたが、画像が表示されなかったため、以下のように修正して正しく表示できるようにしました。
以下のファイルをAndroidプロジェクト内に配置してください。

CustomImageCircleRenderer.cs
using Android.Graphics;
[assembly: ExportRenderer(typeof(Xamarin.Forms.Image), typeof(CustomImageCircleRenderer))]
public class CustomImageCircleRenderer : ImageRenderer
{
    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        //baseを呼ぶとOutOfMemmoryが発生しますのでコメントアウト
        //base.OnElementPropertyChanged(sender, e);

        ImageSource source = Element.Source;

        if ((Element.Width <= 0 ||
                Element.Height <= 0 ||
                _isDecoded) &&
            (e.PropertyName != "Source" || source == null))
        {
            return;
        }

        try
        {
            var width = (int)Element.Width;
            var height = (int)Element.Height;

            //非同期だとListViewに間違った画像が表示される。
            Bitmap bitmap = ImageService.GetShrinkedBitmap(source, width, height);

            //画像を丸型に変更
            Bitmap circleBitmap = CustomImageCircleRenderer.GetCircularBitmap(bitmap);

            //オリジナルのイメージコントロールに修正した画像ファイルをセットします。
            Control.SetImageBitmap(circleBitmap));

        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message + System.Environment.NewLine +
                                    ex.StackTrace);
        }
    }
    //画像を丸型に編集する
    private static Bitmap GetCircularBitmap(Bitmap bitmap)
    {
        if (bitmap == null)
        {
            return null;
        }
        float radius = bitmap.Width > bitmap.Height ?
                                        ((float)bitmap.Height) / 2f :
                                        ((float)bitmap.Width) / 2f;
        if (radius <= 0)
{
radius = 0;
}
else
{
radius -= 2;
}

//ベースとなる画像の丸型設定
Bitmap canvasBitmap = Bitmap.CreateBitmap(bitmap.Width,
bitmap.Height,
Bitmap.Config.Argb8888);
BitmapShader shader = new BitmapShader(bitmap,
Shader.TileMode.Clamp,
Shader.TileMode.Clamp);
Paint basePaint = new Paint();
basePaint.AntiAlias = true;
basePaint.SetShader(shader);

//白い枠の設定
var path = new Android.Graphics.Path();
path.AddCircle(bitmap.Width / 2, bitmap.Height / 2, radius, Android.Graphics.Path.Direction.Ccw);
var whitePaint = new Paint();
whitePaint.AntiAlias = true;
whitePaint.StrokeWidth = 2;
whitePaint.SetStyle(Paint.Style.Stroke);
whitePaint.Color = global::Android.Graphics.Color.White;

//画像を加工する
Canvas canvas = new Canvas(canvasBitmap);
canvas.DrawPath(path, whitePaint); //白枠表示する
canvas.DrawCircle(bitmap.Width / 2, bitmap.Height / 2,
radius - 1, basePaint); //丸型の画像に加工する

        return canvasBitmap;
    }
}

※画像を縮小する関数ImageService.GetShrinkedBitmapにつきましては以下の記事にてご紹介しています。
http://itblogdsi.blog.fc2.com/blog-entry-166.html


2.iOSでの実装方法

こちらはオーバーライドしているメソッドの引数の型が違うぐらいで、ほぼXamarinの公式ブログに書かれている通りで描画ができました。
カスタムレンダラー内にて画像を編集します。以下のファイルをiOSプロジェクト内に配置してください。

CustomImageCircleRenderer.cs
[assembly: ExportRenderer(typeof(Xamarin.Forms.Image), typeof(CustomImageCircleRenderer))]
public class CustomImageCircleRenderer : ImageRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
    {
        base.OnElementChanged(e);

        try
        {
            if (e.OldElement != null || Element == null)
            return;

            CreateCircle();
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message + System.Environment.NewLine +
                                    ex.StackTrace);
        }
    }

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        try
        {
            if (e.PropertyName == VisualElement.HeightProperty.PropertyName ||
                e.PropertyName == VisualElement.WidthProperty.PropertyName)
            {
                CreateCircle();
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message + System.Environment.NewLine +
                                    ex.StackTrace);
        }
    }

    private void CreateCircle()
    {
        try
        {
            double min = Math.Min(Element.Width, Element.Height);
            Control.Layer.CornerRadius = (float)(min / 2.0);
            Control.Layer.MasksToBounds = false;
            Control.Layer.BorderColor = Color.White.ToCGColor();
            Control.Layer.BorderWidth = 2;
            Control.ClipsToBounds = true;
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message + System.Environment.NewLine +
                                    ex.StackTrace);
        }
    }
}

あとは実際にXAMLを表示するだけでImageコントロールが丸形に変更されて表示されていることが確認できると思います。カスタムレンダラーは配置するだけでお手軽コードです。


参考URL
https://blog.xamarin.com/elegant-circle-images-in-xamarin-forms/





当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
http://itblogdsi.blog.fc2.com/blog-entry-81.html


関連記事

コメント

コメントの投稿
非公開コメント

アルバム

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語・データベース】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
Oracle10g SQLServer2008R2 SQLAnywhere8/11/16
ActiveReport CrystalReport ReportNet(IBM)
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。