質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.21%

Xamarin.forms BoxViewに角丸をつける

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,292

gucchi28

score 29

こんにちは。
Xamarin.formsのBoxViewコントロールについて質問です。

BoxViewに角丸をつけたいのですが、
方法として、対象がiOSの場合
⑴ カスタムレンダラを使用して、iOSプラットフォームで記述する
⑵ Effects機能を使用して、iOSプラットフォームで記述する
を検討しています。

⑴の場合は、描画時にsharedプロジェクト側で指定した大きさにならず、
⑵の場合は、iOS側でBoxViewをUIViewとして受け取れず(Nullになる)、うまくいきません。

何かソリューションを持っている方いらっしゃいますか?

⑴のsharedプロジェクト側コード

namespace Test
{
    public class MyBoxView : BoxView
    {

        public Color StrokeColor { get; set; } //ボーダ色
        public Color FillColor { get; set; } //塗りつぶし色

        public int LineWidth { get; set; } //ボーダの幅(0px~10px)
        public float Radius { get; set; } //角丸(0%~50%)

        public MyBoxView(Color fillColor, Color strokeColor, int lineWidth, float radius)
        {
            FillColor = fillColor;
            StrokeColor = strokeColor;
            LineWidth = lineWidth;
            Radius = radius;

            //デフォルト値でサイズとレイアウトを設定
            WidthRequest = 100;
            HeightRequest = 100;
            HorizontalOptions = LayoutOptions.Center;
            VerticalOptions = LayoutOptions.Center;
        }
    }

    public class BoxViewTest : ContentPage
    {
        public BoxViewTest()
        {
            var layout = new AbsoluteLayout();

            var myBox = new MyBoxView(Color.Gray, Color.Yellow, 1, 10);
            AbsoluteLayout.SetLayoutFlags(myBox, AbsoluteLayoutFlags.All);
            AbsoluteLayout.SetLayoutBounds(myBox, new Rectangle(0, 0.5, 1, 0.1));
            layout.Children.Add(myBox);

            Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0);
            Content = layout;
        }
    }
}

⑴のiOSプロジェクト側コード

//MyBoxViewのレンダラーをMyBoxViewRendererに変更する
[assembly: ExportRenderer(typeof(MyBoxView), typeof(MyBoxViewRenderer))]

namespace Test.iOS
{
        public override void Draw(CGRect rect)
        {
            //デフォルトの描画を無効にする
            //base.Draw(rect); 

            //モデルオブジェクトの取得
            var myBoxView = (MyBoxView)Element; //Xamarin.Forms 1.0.6186 では、Modelでした
            using (var context = UIGraphics.GetCurrentContext())
            {
                //塗りつぶしの色を指定
                context.SetFillColor(myBoxView.FillColor.ToCGColor());
                //ボーダの色を指定
                context.SetStrokeColor(myBoxView.StrokeColor.ToCGColor());
                //ボーダの幅を指定
                context.SetLineWidth(myBoxView.LineWidth);
                //ボーダの分だけ四角のサイズを小さくする
                var rectangle = Bounds.Inset(myBoxView.LineWidth, myBoxView.LineWidth);
                //サイズ(幅)の半分を50%として、radiusを求める
                var radius = (float)((rectangle.Width / 2) * (myBoxView.Radius / 50));

                //描画
                var path = CGPath.FromRoundedRect(rectangle, radius, radius);
                context.AddPath(path);
                context.DrawPath(CGPathDrawingMode.FillStroke);
            }
        }
}

⑵のsharedプロジェクト側コード

namespace Test
{
    public class BoxViewTest : ContentPage
    {
        public BoxViewTest()
        {
            var layout = new AbsoluteLayout();
            var box = new BoxView
            {
                BackgroundColor = Color.Blue
            };
            AbsoluteLayout.SetLayoutFlags(box, AbsoluteLayoutFlags.All);
            AbsoluteLayout.SetLayoutBounds(box, new Rectangle(0.5, 0.5, 0.8, 0.5));
            layout.Children.Add(box);
            box.Effects.Add(Effect.Resolve("Test.TestEffects"));

            Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0);
            Content = layout;
        }
    }
}

⑵のiOSプロジェクト側コード

[assembly: ResolutionGroupName("Test")]
[assembly: ExportEffect(typeof(TestEffects), "TestEffects")]

namespace Test.iOS.Effects
{
    public class TestEffects : PlatformEffect
    {
        protected override void OnAttached()
        {
            var box = Control;

            // ここでboxがnull
            if (box == null)
            {
                return;
            }
            box.Layer.BorderWidth = 10;
            box.Layer.BorderColor = UIColor.Black.CGColor;
            box.Layer.CornerRadius = 10;
            box.ClipsToBounds = true;
        }

        protected override void OnDetached()
        {
        }

    }
}

以上、よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

この場合は Control ではなく Container プロパティの方を参照すれば期待通りの動作になると思います。

Effectの Container にはRendererの参照、 Control にはRendererが抱えるネイティブコントロールの参照がセットされます。

iOSの場合、BoxViewRndererは子Viewを持っていないため、Controlプロパティはnullとなります。

Rendererの定義

// iOSのBoxRendererはVisualElementRenderer<T>から派生しており、子を持たない
public class BoxRenderer : VisualElementRenderer<BoxView>

// 他のほとんどのViewのRendererはViewRenderer<TView, TNativeView>から派生しており
// 第2型引数のネイティブコントロールがEffectのControlプロパティに渡される
public class ButtonRenderer : ViewRenderer<Button, UIButton>

iOSの場合、RendererはUIViewから派生しているので、Container.Layerに対して角丸等を設定すればOKです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/20 18:12

    ご回答いただきありがとうございます。
    Containerプロパティを参照することでうまくできました。
    大変助かりました、ありがとうございました。

    キャンセル

  • 2016/12/22 10:15

    すみません、追加質問です。
    iOSでは、UIViewで角丸をつけることができましたが、
    Androidで、ViewGroupで角丸をつけることに苦戦しておりまして、
    調査したところ、XMLで記述すれば角丸をつけることが可能みたいなのですが、
    XamarinでXMLを使う方法が不明であり、また、C#で統一して書きたいと思っています。
    ソリューションはありますでしょうか?

    キャンセル

  • 2016/12/23 23:50

    Androidの場合はBackgroundプロパティにGradientDrawableなどをセットして、それに対してCornerRadiusを設定するといいと思います。
    ただし、AndroidのBoxRendererではBoxView.Colorの色を(Androidの)View.SetBackgroundColorにマッピングしているため、これをGradientDrawable.SetColorにマッピングする独自のRendererを作ってBoxViewに対応するRendererとして差し替えるようにしないと思った通りの動作にならないかもしれません。

    https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.Android/Renderers/BoxRenderer.cs

    キャンセル

  • 2016/12/26 09:41

    ご回答いただきありがとうございます。
    一筋縄ではいかないのですね、、
    トライしてみます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.21%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る