fc2ブログ

記事一覧

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


関連記事

コメント

コメントの投稿

※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。

 入力されていないコメントには返信しませんのであらかじめご了承くださいませ。

※ニックネームでも良いので必ずご入力ください。

    

※必ずご入力ください。

    
    

※必ずご入力ください。

※技術的な質問には環境やエラーについて正確かつ詳細にお教えください。

・正確なエラーの内容

・Windowsのバージョン番号

・Visual Studioのバージョン

・機器の型番

・アプリやソフトのバージョン

    

カテゴリ別記事一覧

広告

プロフィール

石河 純


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

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Catalina 10.15 / Mojave 10.14 / High Sierra 10.13 / Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
【データベース】
Oracle 10g/9i
SQLServer 2016/2008R2/2005/2000
SQLAnywhere 16/11/8
【BI/レポートツール】
Cognos ReportNet (IBM)
Microsoft PowerBI
ActiveReport (GrapeCity)
CrystalReport
【OCX関連】
GrapeCity InputMan SPREAD MultiRow GridView
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS jQuery IIS6/7 apache2

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