SetNeedsDisplay导致应用程序在TouchesMoved事件中崩溃

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SetNeedsDisplay导致应用程序在TouchesMoved事件中崩溃相关的知识,希望对你有一定的参考价值。

在视觉工作室2017中使用xamarin for windows。我有UIScrollView with zoom和UIView作为缩放视图:

public class PlanMarkingPageRenderer : PageRenderer
{
    private UIScrollView scrollView;
    private PlanMarkingView planView;
    private ToolbarItem markItem;
    private bool _markEnabled = false;

    private nfloat _minScale;
    private nfloat _zoomScale;

    public bool MarkEnabled
    {
        get
        {
            return _markEnabled;
        }
        set
        {
            _markEnabled = value;

            scrollView.ScrollEnabled = _markEnabled;

            if (_markEnabled)
            {
                markItem.Text = "Zoom";

                scrollView.MinimumZoomScale = _zoomScale;
                scrollView.MaximumZoomScale = _zoomScale;
                planView.MarkEnabled = true;
                scrollView.MultipleTouchEnabled = false;
                scrollView.ScrollEnabled = false;
                scrollView.DelaysContentTouches = false;
            }
            else
            {
                markItem.Text = "Mark";

                scrollView.MinimumZoomScale = _minScale;
                scrollView.MaximumZoomScale = 1;
                planView.MarkEnabled = false;
                scrollView.MultipleTouchEnabled = true;
                scrollView.ScrollEnabled = true;
                scrollView.DelaysContentTouches = true;
            }
        }
    }

    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);

        var page = e.NewElement as PlanMarkingPage;

        markItem = new ToolbarItem("Mark", null, () =>
        {
            MarkEnabled = !MarkEnabled;
        });

        page.ToolbarItems.Add(markItem);

        var view = NativeView;

        scrollView = new UIScrollView() { Frame = UIScreen.MainScreen.Bounds };
        var img1 = FromUrl(@"");

        var img = img1.CGImage;
        scrollView.ContentSize = img1.Size;
        var scrollViewFrame = scrollView.Frame;

        var scaleWidth = scrollViewFrame.Size.Width / img.Width;
        var scaleHeight = scrollViewFrame.Size.Height / img.Height;
        _minScale = (nfloat)Math.Min(scaleHeight, scaleWidth);

        scrollView.MinimumZoomScale = _minScale;
        scrollView.MaximumZoomScale = 1;
        scrollView.ZoomScale = _minScale;

        planView = new PlanMarkingView() { Frame = new CGRect(0, 0, img.Width, img.Height) };

        planView.ContentMode = UIViewContentMode.Redraw;
        planView.Image = img;
        scrollView.AddSubview(planView);

        scrollView.ViewForZoomingInScrollView += (UIScrollView sv) => { return planView; };

        view.AddSubview(scrollView);
        scrollView.ZoomScale = _minScale;
        _zoomScale = _minScale;
    }

    static UIImage FromUrl(string uri)
    {
        using (var url = new NSUrl(uri))
        using (var data = NSData.FromUrl(url))
            return UIImage.LoadFromData(data);
    }
}

添加图像,在planView上绘制..缩放和滚动工作正常。现在,我想用触摸画一些东西。

SetNeedsDisplay()一致后,我的应用程序在一次或几次移动后崩溃

public class PlanMarkingView : UIView
{
    public bool MarkEnabled { get; set; }
    public CGImage Image;

    CGPoint initialPoint;
    CGPoint latestPoint;

    public PlanMarkingView()
    {            
    }

    public override void Draw(CGRect rect)
    {
        base.Draw(rect);
    }

    public override void TouchesBegan(NSSet touches, UIEvent evt)
    {
        base.TouchesBegan(touches, evt);

        if (!MarkEnabled) return;

        if (touches.AnyObject is UITouch touch)
        {
            initialPoint = touch.LocationInView(this);
        }
    }

    public override void TouchesMoved(NSSet touches, UIEvent evt)
    {
        base.TouchesMoved(touches, evt);

        if (!MarkEnabled) return;

        if (touches.AnyObject is UITouch touch)
        {
            latestPoint = touch.LocationInView(this);
            SetNeedsDisplay();              
        }
    }

    public override void TouchesEnded(NSSet touches, UIEvent evt)
    {
        base.TouchesEnded(touches, evt);
        MarkEnabled = false;
    }

    public override void TouchesCancelled(NSSet touches, UIEvent evt)
    {
        base.TouchesCancelled(touches, evt);
        MarkEnabled = false;
    }
}
答案
    [Export("layerClass")]
    public static Class LayerClass()
    {
        return new Class(typeof(CATiledLayer));
    }

    public PlanMarkingView(nfloat scale)
    {
        tiledLayer = Layer as CATiledLayer;
        tiledLayer.LevelsOfDetail = 8;
        tiledLayer.LevelsOfDetailBias = 3;
        tiledLayer.TileSize = new CGSize(1024f, 1024f);
        tiledLayer.BackgroundColor = UIColor.Red.CGColor;
        tiledLayer.BorderWidth = 0;
    }

    [Export("drawLayer:inContext:")]
    public override void DrawLayer(CALayer layer, CGContext context)
    {
        context.SetFillColor(1f, 1f, 1f, 1f);
        context.FillRect(Bounds);
        context.SaveState();

        context.TranslateCTM(0f, Bounds.Height);
        context.ScaleCTM(1f, -1f);

        context.DrawImage(new CGRect(0, 0, Image.Width, Image.Height), Image);

        if (MarkEnabled && initialPoint != null && latestPoint != null)
        {
        }

        context.RestoreState();
    }

使用CATiledLayer绘制大图像

以上是关于SetNeedsDisplay导致应用程序在TouchesMoved事件中崩溃的主要内容,如果未能解决你的问题,请参考以下文章

setNeedsDisplay 是立即生效还是只是排队等候?

setNeedsLayout 和 setNeedsDisplay

setNeedsDisplay 未按预期在子视图中触发 drawRect

setNeedsDisplay() 和 redraw() 函数调用之间的延迟

使用 setNeedsDisplay 更新 UIView 不起作用

即使在使用 view.setNeedsDisplay() 刷新视图后,.isHidden 属性也不反映对视图的更改