wake-up-neo.com

So legen Sie den Schatteneffekt in ImageView fest

Ich versuche, eine Bildansicht auf Xamarin.Forms (die Android-Plattform anvisieren) mit Schatten zu versehen, und ich habe einige Beispiele im Internet gefunden.

Der PCL-Code ist ziemlich einfach und die Plattform schien auch ziemlich einfach zu sein. Das Rezept ist auf der offiziellen Xamarin-Entwicklerseite erhältlich ist ungefähr so:

[Assembly: ResolutionGroupName("MyGroupName")]
[Assembly: ExportEffect(typeof(LabelShadowEffect), "ShadowEffect")]
namespace MyWorkspace
{
    public class LabelShadowEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            try
            {
                var control = (Control as TextView); // TextView have the SetShadowLayer method, but others views don't

                var effect = (ShadowEffect)Element.Effects.FirstOrDefault(e => e is ShadowEffect);
                if (effect != null)
                {
                    float radius = effect.Radius;
                    float distanceX = effect.DistanceX;
                    float distanceY = effect.DistanceY;
                    Android.Graphics.Color color = effect.Color.ToAndroid();
                    control?.SetShadowLayer(radius, distanceX, distanceY, color);
                }
            }
            catch (Exception)
            {               
            }
        }

        protected override void OnDetached() 
        { 
        }
    }
}

Ich habe also festgestellt, dass dieses Rezept nur für Komponenten funktioniert, die mit TextView gerendert werden (das ist die einzige Klasse mit der SetShadowLayer-Methode). In anderen Quellen Ich habe etwas generischeres gesehen wie:

public class ShadowEffect : PlatformEffect
{
    protected override void OnAttached ()
    {
        Container.Layer.ShadowOpacity = 1;
        Container.Layer.ShadowColor = UIColor.Black.ToCGColor;
        Container.Layer.ShadowRadius = 6;
    }

    protected override void OnDetached ()
    {
        Container.Layer.ShadowOpacity = 0;
    }
}

Durch die Verwendung von UIColor stelle ich fest, dass es sich um eine iOS-Plattform handelt. So etwas auf Android-Ansichten nicht. Ich habe mir den Quellcode von XF FrameRenderer angesehen, konnte aber nicht verstehen, wie der Schatteneffekt funktioniert.

Kann mir jemand dabei helfen?

15

Leider gibt es keinen einfachen Weg, um dies für Android zum Laufen zu bringen. Es gibt jedoch einige Optionen, die Sie ausprobieren können.

Option 1

Es gibt mehrere nicht unterstützte Zeichenoperationen für hardwarebeschleunigte Layer , die SetShadowLayer für Ansichten ohne Text beinhalten.

Um den SetShadowLayer-Renderer für eine Nicht-Textansicht zu erhalten, müssen Sie den LayerType-Renderer als SOFTWARE setzen, wie in dieser Lösung beschrieben.

SetLayerType(LayerType.Software, null);

Der größte Nachteil ist natürlich, dass es sich um ein Leistungsproblem handeln kann.

Option 2

Die zweite Option ist die Verwendung eines radialen Farbverlaufs, um den Schatten zu emulieren. Ich hatte es als Renderer implementiert (aber Sie sollten es auch als Effekt implementieren können). Das Ergebnis ist natürlich nicht so groß wie ein verschwommener Schatteneffekt. Sie müssen auch die rechte Variable Padding einstellen, um Platz für den Schatten zum Rendern zu lassen und unter dem Bild sichtbar zu sein.

protected override void DispatchDraw(global::Android.Graphics.Canvas canvas)
{
    try
    {
        var nativeCtrl = Control;
        var formsElement = Element;
        if (nativeCtrl == null || formsElement == null)
        {
            base.DispatchDraw(canvas);
            return;
        }

        //convert from logical to native metrics if need be
        var shadowDistanceX = 10f;
        var shadowDistanceY = 10f;
        var shadowRadius = 5f;
        var shadowOpacity = .5f;
        var shadowColor = Color.Black;
        var cornerRadius = 0.2f;

        var bounds = formsElement.Bounds;

        var left = shadowDistanceX;
        var top = shadowDistanceY;
        var right = Width + shadowDistanceX;
        var bottom = Height + shadowDistanceY;

        var rect = new Android.Graphics.RectF(left, top, right, bottom);

        canvas.Save();
        using (var Paint = new Android.Graphics.Paint { AntiAlias = true })
        {
            Paint.SetStyle(Android.Graphics.Paint.Style.Fill);

            var nativeShadowColor = shadowColor.MultiplyAlpha(shadowOpacity * 0.75f).ToAndroid();
            Paint.Color = nativeShadowColor;

            var gradient = new Android.Graphics.RadialGradient(
                0.5f, 0.5f,
                shadowRadius,
                shadowColor.ToAndroid(),
                nativeShadowColor,
                Android.Graphics.Shader.TileMode.Clamp
            );
            Paint.SetShader(gradient);

            //convert from logical to native metrics if need be
            var nativeRadius = cornerRadius;  
            canvas.DrawRoundRect(rect, nativeRadius, nativeRadius, Paint);

            var clipPath = new Android.Graphics.Path();
            clipPath.AddRoundRect(new Android.Graphics.RectF(0f, 0f, Width, Height), nativeRadius, nativeRadius, Android.Graphics.Path.Direction.Cw);
            canvas.ClipPath(clipPath);
        }
        canvas.Restore();
    }
    catch (Exception ex)
    {
        //log exception
    }

    base.DispatchDraw(canvas);
}   

Option # 3

Eine andere Option wäre die Verwendung von SkiaSharp für Forms - d. H. Das Erstellen einer Containeransicht (oder einer Layeransicht), die den Schatten um die untergeordnete Ansicht (Bild) rendert. Sie können das Bild auch von SkiaSharp rendern lassen oder ein XF-basiertes Bildsteuerelement in das Layout einbetten.

protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)
{
    var imgInfo = args.Info;
    var surface = args.Surface;
    var canvas = surface.Canvas;

    var drawBounds = imgInfo.Rect;
    var path = new SKPath();
    var cornerRadius = 5f;

    if (cornerRadius > 0)
    {
        path.AddRoundedRect(drawBounds, cornerRadius, cornerRadius);
    }
    else
    {
        path.AddRect(drawBounds);
    }

    using (var Paint = new SKPaint()
    {
        ImageFilter = SKImageFilter.CreateDropShadow(
                                        offsetX,
                                        offsetY,
                                        blurX,
                                        blurY,
                                        color,
                                        SKDropShadowImageFilterShadowMode.DrawShadowOnly),
    })
    {
        canvas.DrawPath(path, Paint);
    }
}
6
G.Sharada

Bitte versuchen Sie es mit diesem Code

<Frame OutlineColor="Transparent" Padding="0" CornerRadius="0" VerticalOptions="Center" BackgroundColor="Teal">
    <Image Source="Imagename" Aspect="Fill" />
</Frame>
4

Ich empfehle, die Eigenschaft Elevation anstelle von ShadowLayer zu verwenden. Android fügt den korrekten Schatten basierend auf der von Ihnen angegebenen Höhe selbst hinzu und hält sich an Material Design.

Für diesen Ansatz müssen Sie jedoch einen benutzerdefinierten Renderer verwenden und einen anderen Renderer für iOS/UWP erstellen.

0
sme