Git Product home page Git Product logo

ncontrol's Introduction

NControl

NControl is a Xamarin.Forms wrapper control built around the NGraphics library enabling developers to create custom controls without the need for custom renderers.

The library contains the NControlView class where real custom cross-platform drawing can be performed without the need for native implementations thanks to the NGraphics library. NControlView can be used both to do custom drawing and to create complex custom controls.

Screenshot Screenshot

Supported Platforms

The library currently supports native renderers for the following platforms:

  • Android
  • iOS Unified
  • Windows Phone
  • Windows Store

Installation

Add the Nuget packages to your iOS, Android and Forms-project.

Remember to to add calls to NControlViewRenderer.Init() after Forms.Init() in your AppDelegate and in your MainActivity.

Example Usage

In your Xamarin.Forms project, add a new NControlView element to your page in the constructor and provide a drawing function where your custom drawing is performed:

  Content = new NControlView {
      DrawingFunction = (canvas, rect) => {
          canvas.DrawLine(rect.Left, rect.Top, rect.Width, rect.Height, NGraphics.Colors.Red);
          canvas.DrawLine(rect.Width, rect.Top, rect.Left, rect.Height, NGraphics.Colors.Yellow);
      }
  };

Subclassing

You can also create a subclass of the NControlView class and override its Draw function to add your own custom drawing:

public class MyControl: NControlView
{
  public override void Draw(NGraphics.ICanvas canvas, NGraphics.Rect rect)
  {
    canvas.DrawLine(rect.Left, rect.Top, rect.Width, rect.Height, NGraphics.Colors.Red);
    canvas.DrawLine(rect.Width, rect.Top, rect.Left, rect.Height, NGraphics.Colors.Yellow);
  }
}

Complex Controls

NControlView supports containing other controls since it inherits from the ContentView class. Building composite controls is as simple as setting the Content property of your subclassed control:

public class MyControl: NControlView
{
  public MyControl()
  {
    Content = new Label {BackgroundColor = Xamarin.Forms.Color.Transparent};
  }
  
  public override void Draw(NGraphics.ICanvas canvas, NGraphics.Rect rect)
  {
    canvas.DrawLine(rect.Left, rect.Top, rect.Width, rect.Height, NGraphics.Colors.Red);
    canvas.DrawLine(rect.Width, rect.Top, rect.Left, rect.Height, NGraphics.Colors.Yellow);
  }
}

Now your custom control will have a label that can draw text in the control. Remember that you can set the Content property to point to anything as long as it is a VisualElement. This means that you can add layouts containing other controls as well as a single control.

Invalidation

If you need to invalide the control when a property has changed, call the Invalidate() function to redraw your control:

public class MyControl: NControlView
{
  private Xamarin.Forms.Color _foregroundColor = Xamarin.Forms.Color.Red;
  public Xamarin.Forms.Color ForegroundColor { 
    get 
    { 
      return _foregroundColor; 
    }
    set 
    { 
      _foregroundColor = value;
      Invalidate();
    }
  }
  
  public override void Draw(NGraphics.ICanvas canvas, NGraphics.Rect rect)
  {
    canvas.DrawLine(rect.Left, rect.Top, rect.Width, rect.Height, new NGraphics.Color(_foregroundColor.R, _foregroundColor.G,
      _foregroundColor.B, _foregroundColor.A));
  }
}

Touch Events

The NControlView class also handles touch events - look at the CircularButtonControl for an example of how this can be used.

Demo Controls

The demo solution contains a few different controls based on the NControlView class:

The ProgressControl and the CircularButtonControl both internally uses the FontAwsomeLabel to display glyphs from the Font Awesome Icon font.

Notes

Note that the ProgressControl and the CircularButtonControl contains animations to make the user experience more alive. The demo solution also uses animation to add some eye candy to the demo itself.

ncontrol's People

Contributors

awolf avatar blueraja avatar chrfalch avatar frankneumann avatar joshuanovak919 avatar kolodiichyk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ncontrol's Issues

Doesn't seem to work on WP8

It seems that drawing does not work on WP8 (or that I'm missing something during the installation :) ). I have created a Xamarin.Forms Portable project, installed NControl via NuGet for all four projects in the solution, and changed the default code as follows:

            MainPage = new ContentPage
            {
                Content = new StackLayout
                {
                    VerticalOptions = LayoutOptions.Center,
                    Children = {
                        new Label {
                            XAlign = TextAlignment.Center,
                            Text = "Welcome to Xamarin Forms!"
                        },
                        new NControlView()
                        {
                            DrawingFunction = (canvas, rect) => {
                                canvas.DrawEllipse(rect, Pens.Red, Brushes.Green);
                            },
                            WidthRequest = 200, HeightRequest = 200
                        }
                    }
                }
            };

This works perfectly fine on Android, but does not seem to work for the Windows Phone project. I also tried retargetting the WP project to Windows Phone Silverlight 8.1, but still nothing happens. Is this an issue or am I simply missing something?

Windows RT version - CanvasCanvas.MeasureText is not working correctly

MeasureText gives allways a an empty Size back.
I repleaced the implementation with this one:

public Size MeasureText(string text, Font font)
    {
      if (text == " ")
      {
        text = "\u00A0";
      }

      var textBlock = new TextBlock
      {
        Text = text,
        FontFamily = new FontFamily(font.Family),
        FontSize = font.Size,
        VerticalAlignment = VerticalAlignment.Top,
        HorizontalAlignment = HorizontalAlignment.Left
      };

      textBlock.Measure(new Windows.Foundation.Size(double.MaxValue, double.MaxValue));
      return new Size(textBlock.DesiredSize.Width, textBlock.DesiredSize.Height);
    }

Now it is working for me.

Regards,
Sörnt

Upgrade to Xamarin Forms 2.0

Hi,

First of all, thanks for your beautiful library !

I'm experiencing an issue on my Windows Phone Silverlight (8.1) project since I migrated to X.Forms 1.5 : it can't seem to resolve the dependency to X.Forms. It seems he's trying to reflect on version 1.4, and redirection is not enough to make it work.

Here is the error message :
App.xaml(1,1,1,1): error : Cannot resolve dependency to assembly 'Xamarin.Forms.Platform.WP8, Version=1.4.0.0, Culture=neutral, PublicKeyToken=null' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event

I downloaded the sources, rebuilt the nuget package (after updating xamarin forms to 1.5 for each subproject) and it works like a charm. So I'm guessing it's quite a minor problem (though blocking if you don't know how to rebuild / install a nuget package)

Thanks again ! You're awesome !

DrawingFunction is nerver called on iOS

On iOS, DrawingFunction is nerver called when NControlView is added to the Layout that is set IsVisible property to false.
On Android, it works correctry.

Reproduction code:

public App()
{
    var nControlView = new NControlView {
        HeightRequest = 100,
        WidthRequest = 100,
        DrawingFunction = (canvas, rect) => {
            // It's never called on iOS.
            canvas.FillEllipse(rect, NGraphics.Colors.Green);
        },
    };

    var grid = new Grid {
        IsVisible = false,
        Children = {
            nControlView,
        },
    };

    var button = new Button {
        Text = "Toggle Visibility"
    };
    button.Clicked += (sender, e) => grid.IsVisible = !grid.IsVisible;

    MainPage = new ContentPage {
        Content = new StackLayout {
            VerticalOptions = LayoutOptions.Center,
            HorizontalOptions = LayoutOptions.Center,
            Children = {
                grid,
                button,
            }
        }
    };
}

I tapped the button and set grid.IsVisible to true, but DrawingFunction was not called.

Update points

Is there a way to update points? I made a line with endpoint variables that I invalidate and it doesn't seem to update. I'm not sure if i'm doing it wrong, or if there isn't a way to do this.

Variable definitions:

private double _endX = 0;
public double EndX { 
    get 
    { 
        return _endX; 
    }
    set 
    { 
        _endX = value;
        Invalidate();
    }
}

private double _endY = 0;
public double EndY { 
    get 
    { 
        return _endY; 
    }
    set 
    { 
        _endY = value;
        Invalidate();
    }
}

Line:
canvas.DrawLine (20, 20, EndX, EndY, Colors.Blue, 2);

TouchesXXX does not work on Custom Cells [iOS only]

I have a custom cell in Xamarin Forms (inheriting from ViewCell) with an AbsoluteLayout, containing a control inheriting from NControlView.
These Cells are in a ListView.

Somehow, TouchesBegan never gets called on iOS. I do not think I am missing anything, as it works on Android and WP.

It think it might come from the UITouchesGestureRecognizer, but I do not really know how to fix it.

XAML Examples

How would you use these in XAML? I tried using the RoundedBorderControl, it shows up, but just shows a square instead of having rounded borders.

Here is my code:

In ContentPage tag:
xmlns:qcontrols="clr-namespace:MyApp.Controls;assembly=MyApp"

XAML control code:
<qcontrols:RoundedBorderControl BackgroundColor="Red" CornerRadius="80" WidthRequest="100" HeightRequest="100" />

Control Code:

using System;
using Xamarin.Forms;
using NControl.Plugins.Abstractions;
using NGraphics;

namespace MyApp.Controls
{
    /// <summary>
    /// Rounded border control.
    /// </summary>
    public class RoundedBorderControl: NControlView
    {
        #region Private Members

        /// <summary>
        /// The color of the background.
        /// </summary>
        private Xamarin.Forms.Color _backgroundColor;

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="NControlDemo.FormsApp.Controls.RoundedBorderControl"/> class.
        /// </summary>
        public RoundedBorderControl()
        {
            base.BackgroundColor = Xamarin.Forms.Color.Transparent;
        }

        #region Properties

        /// <summary>
        /// The corner radius property.
        /// </summary>
        public static BindableProperty CornerRadiusProperty = 
            BindableProperty.Create<RoundedBorderControl, int> (p => p.CornerRadius, 8);

        /// <summary>
        /// Gets or sets the corner radius.
        /// </summary>
        /// <value>The corner radius.</value>
        public int CornerRadius 
        {
            get
            {
                return (int)GetValue(CornerRadiusProperty);
            }
            set
            {
                SetValue(CornerRadiusProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the color which will fill the background of a VisualElement. This is a bindable property.
        /// </summary>
        /// <value>The color of the background.</value>
        public new Xamarin.Forms.Color BackgroundColor
        {
            get
            {
                return _backgroundColor;
            }
            set
            {
                _backgroundColor = value;
                Invalidate();
            }
        }

        #endregion

        #region Drawing

        /// <summary>
        /// Draw the specified canvas.
        /// </summary>
        /// <param name="canvas">Canvas.</param>
        /// <param name="rect">Rect.</param>
        public override void Draw(NGraphics.ICanvas canvas, NGraphics.Rect rect)
        {
            base.Draw(canvas, rect);

            var backgroundBrush = new SolidBrush(new NGraphics.Color(_backgroundColor.R,
                _backgroundColor.G, _backgroundColor.B, _backgroundColor.A));

            var curveSize = CornerRadius;
            var width = rect.Width;
            var height = rect.Height;
            canvas.DrawPath(new PathOp []{ 
                new MoveTo(curveSize, 0),
                // Top Right corner
                new LineTo(width-curveSize, 0),
                new CurveTo(
                    new NGraphics.Point(width-curveSize, 0),
                    new NGraphics.Point(width, 0),
                    new NGraphics.Point(width, curveSize)
                ),
                new LineTo(width, height-curveSize),
                // Bottom right corner
                new CurveTo(
                    new NGraphics.Point(width, height-curveSize),
                    new NGraphics.Point(width, height),
                    new NGraphics.Point(width-curveSize, height)
                ),
                new LineTo(curveSize, height),
                // Bottom left corner
                new CurveTo(
                    new NGraphics.Point(curveSize, height),
                    new NGraphics.Point(0, height),
                    new NGraphics.Point(0, height-curveSize)
                ),
                new LineTo(0, curveSize),
                new CurveTo(
                    new NGraphics.Point(0, curveSize),
                    new NGraphics.Point(0, 0),
                    new NGraphics.Point(curveSize, 0)
                ),
                new ClosePath()
            }, null, backgroundBrush);

        }

        #endregion
    }
}

How to create a blur effect

Anyone know how to create a blur effect with NControl? I can't seem to figure out how I could handle this.

How to use TapGestureRecognizer

How can I use the TapGestureRecognizer on my custom control? It doesn't seem to work.

I tried this in my page:

<ctrls:MyControl.GestureRecognizers>
   <TapGestureRecognizer Tapped="OnMyControlClicked"/>
</ctrls:MyControl.GestureRecognizers>

Invalidate when inner content changes

How to I go about invalidating a control made with NControlView when a child has changed? For example if I have a control with a label inside it and the value of the label changes, I need to have the element redraw so the width is correct.

Padding is incorrectly included in the draw rect

If I add padding to the NControlView, the rect parameter of the Draw method includes the padding.

This seems incorrect to me, since my understanding of padding is that you don't draw on it.

Additionally, this is not easy to correct by simply subtracting the padding from the rect, since the units have changed. For example, on my Android test device, a padding thickness of 50 in the control becomes 100 in the draw rect size, and I'm not sure how to undo this conversion in a device-independent way.

It sure would be nice if NControlView correctly removed the padding from the rect to avoid this complexity.

Thanks!

Double drawing of controls in Android

If you create composite controls (controls containing other controls) with custom drawing you might experience that Android is drawing the child controls twice if you are scaling or using padding.

Reproduction:

  1. Create a new project with a new custom control
  2. Add an inner image and set its scaling to 2
  3. Run on Android

Observe that the image is drawn twice, one with and one without scaling.

TouchesEnded is not called on iOS

TouchesEnded is invoked after TouchesBegan on Android, but not on iOS.

I noticed that all of the demo controls are either treating TouchesCancelled the same as TouchesEnded, or are only using TouchesBegan, which explains why the demos work on both Android and iOS, but my code that is working on Android does not work on iOS.

The behavior that I expect is that TouchesCancelled should be handled differently than TouchesEnded and should not invoke, for example, a Click event.

Win RT version - Renderer crashes when view gets removed from page

Within NControlViewRenderer.OnElementChanged the renderer crashes when setting the native control SetNativeControl(ctrl); while the view is getting removed from the page.

I changed the implementation to catch the situation when OnElementChanged is called while the view is going to be removed:

 protected override void OnElementChanged(ElementChangedEventArgs<NControlView> e)
    {

      base.OnElementChanged(e);

      if (e.OldElement != null)
      {
        e.OldElement.OnInvalidate -= HandleInvalidate;
      }

      if (e.NewElement != null)
      {
        e.NewElement.OnInvalidate += HandleInvalidate;
      }

      // I added these three lines.
      if ((e.OldElement != null) && (e.NewElement == null) && (Control == null))
      {
        return;
      }

      if (Control == null)
      {
        var ctrl = new NControlNativeView();
        Canvas = new Canvas();
        Border = new Border
        {
          Child = Canvas,
        };

        ctrl.Children.Add(Border);

        SetNativeControl(ctrl);

        UpdateClip();
        UpdateInputTransparent();
      }

      RedrawControl();
    }

Kind regards,
Sörnt

TouchesBegan is not called on iOS

A short click does not result in a call to TouchesBegan on iOS. A longer press works as expected. This makes for a UI that seems unresponsive.

Short clicks work as expected on Android.

Any plans or anyone working towards UWP support?

I think the title pretty much sums it up.
I was wondering if anyone is working on adding UWP support?
NControl is a really great addition to a Xamarin.Forms project - Whose three big project platforms are iOS, Android and UWP. So having this working in UWP would be great!

Multi-touch (android?)

Hey there -

First off, great library - it's making my life a million times easier.

I've implemented NControl into a Xamarin shared project to create a sort-of cropping tool. I've overridden the Touch events and they're all behaving as expected with the exception that the IEnumerable parameters only contain ONE point. My code shoouuld be set up to iterate through and handle multi-touch, but I'm only seeing the first touch coming through.

(This has only been tested on the Android side - haven't gotten around to swinging the iOS side yet)

Thoughts?

Controls not working in Ad Hoc builds

When I run a debug view on my phone or in the simulator my controls work great, but when I make an Ad Hoc build and run that on my phone they don't show up. Anyone have any ideas?

My Controls code:

using NControl.Abstractions;
using Xamarin.Forms;
using NGraphics;
using System.Diagnostics;
using System.Collections.Generic;

namespace MyApp.Controls
{
    public class HalfRibbon : NControlView
    {
        public static BindableProperty EndPercentageProperty = 
            BindableProperty.Create<HalfRibbon, double> (p => p.EndPercentage, 0.07, 
                BindingMode.OneWay, null, EndPercentageChanged);

        public double EndPercentage 
        {
            get { return (double)GetValue(EndPercentageProperty); }
            set { SetValue(EndPercentageProperty, value); }
        }

        private static void EndPercentageChanged(BindableObject bindable, double oldValue, double newValue)
        {
            (bindable as HalfRibbon).Invalidate();
        }

        public static new BindableProperty BackgroundColorProperty = 
            BindableProperty.Create<HalfRibbon, Xamarin.Forms.Color> (
                p => p.BackgroundColor, Xamarin.Forms.Color.Transparent, BindingMode.OneWay, null, BackgroundColorChanged);

        public new Xamarin.Forms.Color BackgroundColor
        {
            get { return (Xamarin.Forms.Color)GetValue(BackgroundColorProperty); }
            set { SetValue(BackgroundColorProperty, value); }
        }

        private static void BackgroundColorChanged(BindableObject bindable, Xamarin.Forms.Color oldValue, Xamarin.Forms.Color newValue)
        {
            (bindable as HalfRibbon).Invalidate();
        }

        public HalfRibbon ()
        {
        }

        public override void Draw(NGraphics.ICanvas canvas, NGraphics.Rect rect)
        {
            base.Draw(canvas, rect);

            var backgroundBrush = new SolidBrush(new NGraphics.Color(BackgroundColor.R,
                BackgroundColor.G, BackgroundColor.B, BackgroundColor.A));

            var width = (WidthRequest > 0)? WidthRequest : rect.Width;
            var ribbonWidth = Math.Ceiling(width * EndPercentage);
            var height = (HeightRequest > 0)? HeightRequest : rect.Height;

            canvas.DrawPath(new PathOp []{ 
                new MoveTo(0, 0),
                new LineTo(width, 0),
                new LineTo(width - ribbonWidth, height / 2),
                new LineTo(width, height),
                new LineTo(0, height),
                new LineTo(0, 0),
                new ClosePath()
            }, null, backgroundBrush);
        }
    }
}

System.ArgumentNullException: Argument cannot be null [IOS Only]

I get the following error when using NControl to draw a canvas and get the PNG from it. I draw an image from a bytearray to the canvas, some text, and then save the image to a memorystream. This crash only occurs on iOS:

System.ArgumentNullException: Argument cannot be null.
Parameter name: image
  at NGraphics.CGImageImage..ctor (CoreGraphics.CGImage image, Double scale) [0x0000c] in /Users/fak/Dropbox/Projects/NGraphics/Platforms/NGraphics.Mac/ApplePlatform.cs:133
  at NGraphics.ApplePlatform.LoadImage (System.IO.Stream stream) [0x0005e] in /Users/fak/Dropbox/Projects/NGraphics/Platforms/NGraphics.Mac/ApplePlatform.cs:77
  at GroupieCross.ViewModels.CameraViewPageViewModel+<HandleBitmap>c__async4.MoveNext () [0x00000] in /Users/frankgeib/Desktop/GroupieCross/GroupieCross/GroupieCross/ViewModel/ViewModelLocator.cs:11
  at --- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in /Users/builder/data/lanes/1503/6481535e/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003b] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:199
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142
  at System.Runtime.CompilerServices.TaskAwaiter`1[System.Byte[]].GetResult () [0x00000] in <filename unknown>:0
  at GroupieCross.ViewModels.CameraViewPageViewModel+<Accept>c__async1.MoveNext () [0x00013] in /Users/frankgeib/Desktop/GroupieCross/GroupieCross/GroupieCross/ViewModels/GroupMessagePageViewModel.cs:37
  at --- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in /Users/builder/data/lanes/1503/6481535e/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61
  at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>m__0 (System.Object state) [0x00000] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1006
  at UIKit.UIKitSynchronizationContext+<Post>c__AnonStorey0.<>m__0 () [0x00000] in /Users/builder/data/lanes/1503/6481535e/source/maccore/src/UIKit/UIKitSynchronizationContext.cs:24
  at Foundation.NSAsyncActionDispatcher.Apply () [0x00000] in /Users/builder/data/lanes/1503/6481535e/source/maccore/src/Foundation/NSAction.cs:164
  at at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
  at UIKit.UIApplication.Main (System.String[] args, IntPtr principal, IntPtr delegate) [0x00005] in /Users/builder/data/lanes/1503/6481535e/source/maccore/src/UIKit/UIApplication.cs:63
  at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0001c] in /Users/builder/data/lanes/1503/6481535e/source/maccore/src/UIKit/UIApplication.cs:46
  at GroupieCross.Application.Main (System.String[] args) [0x00020] in /Users/frankgeib/Desktop/GroupieCross/GroupieCross/GroupieCross.iOS/AppDelegate.cs:25

Android Pixel Issue

NControl uses pixels on Android, which is fine, but if you setup a control that has parameters like corner radius or anything size related, the size will be different on devices with different densities since the pixels change, but your parameter doesn't. Is there a good way to convert the size without having to use XLabs' IDevice or another library?

Android display density

I've noticed in the demo that while NGraphics.ICanvas appears to work with resolution independent "pixels" on iOS, the Android equivalent works with real pixels.

I haven't yet looked to see what NGraphics offers in this regard, but was wondering whether you think it's something that NControl could/should handle, or if you'd rather leave it up to the control implementations?

p.s. NControl is quite great. Thanks.

Windows Phone RT version

Hi there,

When you nowadays start a new Xamarin.Forms project, no WP Silverlight project get created but a Windows Phone RT project.
After installing NControl, these assemblies are referenced at the WP RT project:

  • NControl
  • NGraphics
  • NGraphics.WindowsPhone

Something like "NControl.WindowsPhone" is missing.

Is it possible to get a WP RT version of NControl?

By the way, the library is awesome! Thank you very much!

interception/propagation of touch events

intercepting touches: in my first example there is a GalleryView (of NControl.Controls) inside of a (vertical) ScrollView:

on android the ScrollView takes control of the touches as soon as there is vertical movement. the GalleryView then snaps back (receives a TouchCancelled).
on ios i cannot scroll vertically when touching the GalleryView. if i touch another control inside of the ScrollView i can scroll but as soon as i touched a GalleryView the vertical scrolling does not work anymore in all cases (haven't found out what's going on exactly).

on android i added a hack for "intercepting" the touches: upon touching the extended GalleryView fires an event which the extended ScrollView reacts to by setting it's InputTransparent to true (and later back to false).

propagating touches: in the second example i tried to implement some scrolling behaviour on my own by creating a class ScrollView2 (great naming, i know) extending NControlView:

the ScrollView2 does not render anything by itself, it only layouts it's children. but because it doesn't render it does not receive touches when a child get touched -- even if said child does not handle touches.
if i set the BackgroundColor of ScrollView2 to anything it receives the touches but only where it is directly touched.

is there any mechanism i overlooked? if not, do you plan to implement something like it?

very slow to invalidate for small chagnes

Hi

The invalidate method is bad for graphics. It should probably allow for partial invalidation or a way not to force a full redrawn.
Let me explain the situation.
Try to create a progressbar that increases from 0 to the full width of the screen. One pixel at a time.

  1. Override Draw, but it gets an empty canvas so you have to draw the full rectangle every time.
  2. Wait for an Invalidate call to redraw everything again.

This is extremely slow. You will see flickering on the control. The options are to either allow for some kind of double buffer so it doesn't flicker or speed it up considerably by allowing partial redraws.

Here just as an example, my code to test it. Just call Progress on a loop from 0 to 1 incrementing by 0.001 for instance (1000 pixels width).

public class MyProgressBar : NControlView
{
public static readonly BindableProperty BarColorProperty =
BindableProperty.Create<MyProgressBar, Xamarin.Forms.Color>
(p => p.BarColor, Xamarin.Forms.Color.Blue);

    public Xamarin.Forms.Color BarColor
    {
        get { return (Xamarin.Forms.Color)GetValue(BarColorProperty); }
        set { SetValue(BarColorProperty, value); }
    }

    public static readonly BindableProperty ProgressProperty =
        BindableProperty.Create<MyProgressBar, double>
    (p => p.Progress, 0);

    public double Progress
    {
        get { return (double)GetValue(ProgressProperty); }
        set {
                SetValue (ProgressProperty, value);
                this.Invalidate ();
        //  }
        }
    }

    public MyProgressBar()
    {
    }

    public override void Draw(NGraphics.ICanvas canvas, NGraphics.Rect rect)
    {
        //if (prevRect == 0) {
            canvas.FillRectangle (rect.X, rect.Y, rect.Width * Progress, rect.Height, Colors.Orange);
    /*      prevRect = rect.Width * Progress;
        } else { // draw only the new lines
            double newWidth=(rect.Width * Progress)-prevRect;
            if (newWidth > 0) {
                canvas.FillRectangle (prevRect, rect.Y, newWidth, rect.Height, Colors.Orange);
                prevRect = prevRect + newWidth;
            }
        }*/
    }
}

NControl resource errors when all packages up to date

I have a Xamarin.Forms class library solution S1 with a few projects, including an Android project with custom renderers, and a solution S2 with a Xamarin.Forms application referencing assemblies from S1. Solution S1 uses Xamarin.Forms 1.3.3.6323 in some platform-independent projects and Xamarin.Forms 2.2.0.31 in other projects, including the one with Android custom renderers. It uses the version 23.3.0 of the “Xamarin.Android.Support.” packages. Solution S2 uses Xamarin.Forms 2.1.0.6529 and Xamarin.Android.Support. 23.0.1.3 in all projects. Both solutions build, but if I upgrade everything to Xamarin.Forms 2.2.0.45 and Xamarin.Android.Support.* 23.3.0 and rebuild first solution S1 and then solution S2 referencing already the rebuilt assemblies from S1, then solution S2 does not compile and complains that there are undefined constants in the file “Resource.Designer.cs” in the Android project. I have tried updating the Android SDK to the newest version, cleaning solution S2, deleting all the “bin” and “obj” folders in S2 and removing the file “Resource.Designer.cs” in S2 before rebuilding S2, I even tried emptying the “C:\Users\” + username + “\AppData\Local\Xamarin\zips” folder before rebuilding, but nothing helps, except for reverting to the initial situation. My goal is to unify the versions of Xamarin.Forms and other packages across both solutions, but I have been failing to achieve that for a week already. Maybe I should unify the version of Xamarin.Forms in S1 and S2 to another version than the latest one, but I don’t know how to determine which one to choose. Please, can you help me solve this?

example error: 'Resource.Attribute' does not contain a definition for 'mediaRouteSettingsDrawable'
concerning line in “Resource.Designer.cs”:

        global::NControl.Controls.Droid.Resource.Attribute.mediaRouteSettingsDrawable = global::MyCompany.MyApplication.Droid.Resource.Attribute.mediaRouteSettingsDrawable;

In the Android project I have all these references:

NControl
NControl.Controls
NControl.Controls.Droid
NControl.Droid
NGraphics
NGraphics.Android

All NuGet packages are up to date.

It is the “MyCompany.MyApplication.Droid.Resource.Attribute” that does not have a member named “mediaRouteSettingsDrawable”. How am I to understand that this member is not generated and at the same time it is expected? How can I fix that? I need to understand this, otherwise I will not move any further.

Problem with iOS input in a control hierarchy

I recently added a button implemented using NControlView on top of another view, and clicking the button also invoked a touch event on the control underneath the button (which broke my scenario).

I was able to fix it with the following modification to the touch handling in my NControlView subclass (which you integrated earlier).

The new code sets the State of the gesture recognizer based on the return value of the Touches* events.

This way, if the control indicates that it handled the touch (by returning true), the gesture recognizer will not propagate the event further, which enables scenarios with overlapping controls that all handle input.

It also makes it consistent with the behavior on Android.

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

            var points = GetTouchPoints(touches);

            if (this._element.TouchesBegan(points))
            {
                this.State = UIGestureRecognizerState.Began;
            }
        }

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

            var points = GetTouchPoints(touches);

            if (this._element.TouchesMoved(points))
            {
                this.State = UIGestureRecognizerState.Changed;
            }
        }

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

            var points = GetTouchPoints(touches);

            if (this._element.TouchesEnded(points))
            {
                this.State = UIGestureRecognizerState.Ended;
            }
        }

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

            var points = GetTouchPoints(touches);

            this._element.TouchesCancelled(points);

            this.State = UIGestureRecognizerState.Cancelled;
        }

CircularButtonControl not showing the Icon on Android

I am using the CircularButtonControl and ProgressControl from XAML and the icon shows correctly on iOS, but not on Android. This is the ContentPage

<ContentPage 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:qcontrols="clr-namespace:NGraph1;assembly=NGraph1"
    x:Class="NGraph1.TestPage"
    Title="Test Title">
    <ContentPage.Content>
            <StackLayout Orientation="Vertical" Padding="5,5,5,0" >
                <qcontrols:ProgressControl BackgroundColor="Green" CornerRadius="80" WidthRequest="100" HeightRequest="100" />
                <qcontrols:CircularButtonControl FAIcon="{x:Static qcontrols:FontAwesomeLabel.FAPlay}"  />
            </StackLayout>
    </ContentPage.Content>
</ContentPage>

Any ideas why?

cannot add projects to my solution

hi there,

love your component (and the NControl.Controls too).

i'm pretty new to the whole xamarin thing and had my fair share of version conflicts and the like. just dropping xamarin nugets into my solution does not work most of the time (does not work with your nugets either). results in those android Resources.designer-stuff errors and from what i've learned that has something to do with incompatible library versions (most likely xamarin forms).

so i decided to pull the sources and add the projects to my solution. works for most projects, e.g. NGraphics.

when i add your projects to my solution though the references of those projects cannot be resolved anymore. that's something i have not encountered so far:
http://imgur.com/IXtS9C1

even though i've manually changed the xamarin forms nuget version to the one in my solution the project just cannot find it, the exclamation mark stays and i cannot compile.

any idea? is there anything special to how you set up your solutions?

edit: btw, the solution to this mess was to create a custom solution in which i added the NGraphics projects as they are and your projects (NControls and NControls.Controls) by creating new projects from scratch and linking the existing source files into them. then i manually added the references so it uses only solution-intern projects. next i added my target version of the xamarin forms nuget for all projects. this way i can be sure everything is compatible and easily add it to my work solution. a long way :)

IsVisible changes should call Invalidate() ?

I could be doing something wrong here, but it seems that if you have a custom NControlView, and it's initially set to IsVisible = false, then if you change it to true, then the control will not render because no Draw() call is made.

So perhaps, NControlView needs to listen to visibility changes and make a call to Invalidate() when it it goes to true?

Setting Android background color causes CircularButtonControl to not draw correctly

Thanks for a great lib! This may be an NGraphics problem, but I saw it while using your library so I will start with you. If I specify a background color, for example in your "Theme.NewSolution" custom theme like so:

    <item name="android:background">#ff0000</item>

None of the custom drawing commands appear to be executed, although I have stepped through the code while debugging and confirmed that they are. See attached images from before and after adding the background setting to your theme.

BEFORE:
1 - before

AFTER:
2 - after

Expose underlying platform on NControlView

Let the NControlView abstract class expose the underlying IPlatform implementation through a simple property. This will make it easy to create images and canvases using the platform implementation.

NControl.UWP ?

Please create NControl.UWP

Is NControl.Win compatible with UWP? How to port
Touch.FrameReported += Touch_FrameReported; to UWP?

public abstract class NControlViewRendererBase : ViewRenderer<NControlView, Border>
{
    protected static void Initialize()
    {
        Touch.FrameReported += Touch_FrameReported; 
    }
}

Handle click with scroll view

Does anyone know the best way to handle the click event when the element is in a scrollview? Right now if I touch on the object I am using NControl for and try to scroll the screen it does not scroll and the touch registers even if I move my finger away from the button.

Android crash (ObjectsDisposedException) when Page gets destroyed

Hi Christian,

the NControlViewRenderer did not proper unsubscribe from the "OnInvalidate" and "OnGetPlatform" Event:

The current Code:

protected override void OnElementChanged(ElementChangedEventArgs<NControlView> e)
{
  base.OnElementChanged(e);

   if (e.OldElement != null)
   {
      e.OldElement.OnInvalidate -= HandleInvalidate;
      e.OldElement.OnGetPlatform -= OnGetPlatformHandler;
   }

   if (e.NewElement != null)
   {
      e.NewElement.OnInvalidate += HandleInvalidate;
      e.NewElement.OnGetPlatform += OnGetPlatformHandler;
    }
...
}

Looks like that for Andorid that method did not get called when relasing the control.

I changed it to this:

private NControlView _currentElement;

protected override void OnElementChanged(ElementChangedEventArgs<NControlView> e)
{
  base.OnElementChanged(e);

  if (e.OldElement != null)
  {
      e.OldElement.OnInvalidate -= HandleInvalidate;
      e.OldElement.OnGetPlatform -= OnGetPlatformHandler;
      _currentElement = null;
  }

  if (e.NewElement != null)
  {
    e.NewElement.OnInvalidate += HandleInvalidate;
    e.NewElement.OnGetPlatform += OnGetPlatformHandler;
    _currentElement = e.NewElement;
  }
...
}

protected override void Dispose(bool disposing)
{
  if ((disposing) && (_currentElement != null))
  {
     _currentElement.OnInvalidate -= HandleInvalidate;
     _currentElement.OnGetPlatform -= OnGetPlatformHandler;
     _currentElement = null;
  }

  base.Dispose(disposing);
}

In my situation the control ist bounded to a VM. When changing a property after the page has been removed, the NControl calls somewhen "Invalidate" which triggers the "OnInvalidate" Event.

Hope that helps.

Sörnt

NControl crashes on Windows Phone

Hi,
NControl is great and i like it, but now, it crashes on WindowsPhone.
Even if i only call
var view = new NControlView();
The App runs into (App.xaml.cs)

// Code to execute if a navigation fails
private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
    if (Debugger.IsAttached)
    {
        // A navigation has failed; break into the debugger

STOPPED HERE Debugger.Break();
}
}

It works fine on Android and iOS
What happens ??

I'm using XF 1.4.4.6392 and NControl 0.5.981

Method 'MeasureText' in type 'NControl.Win.CanvasCanvas' from assembly 'NControl.WP80 (...) does not have an implementation.

So, to reproduce:
1 - Create a Xamarin.Forms portable project (i'm using VS2013)
2 - Install ncontrol and ngraphics on WP and portable
3 - Create any NControlView on XAML or CS page in forms

I'm using Init() just as you do on your sample for WP8.0. And your sample does work on my phone. I just can't reproduce. I already confirmed I'm using all the same versions of every nugget package in both.

Thanks.

  •   $exception  {System.TypeLoadException: Method 'MeasureText' in type 'NControl.Win.CanvasCanvas' from assembly 'NControl.WP80, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
    
    at NControl.WP80.NControlViewRenderer.CreateCanvas(Canvas canvas)
    at NControl.Win.NControlViewRendererBase.RedrawControl()
    at NControl.Win.NControlViewRendererBase.OnElementPropertyChanged(Object sender, PropertyChangedEventArgs e)
    at System.ComponentModel.PropertyChangedEventHandler.Invoke(Object sender, PropertyChangedEventArgs e)
    at System.ComponentModel.PropertyChangedEventHandler.Invoke(Object sender, PropertyChangedEventArgs e)
    at Xamarin.Forms.BindableObject.OnPropertyChanged(String propertyName)
    at Xamarin.Forms.BindableObject.SetValueActual(BindableProperty property, BindablePropertyContext context, Object value, Boolean currentlyApplying, SetValueFlags attributes, Boolean silent)
    at Xamarin.Forms.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes)
    at Xamarin.Forms.BindableObject.SetValue(BindableProperty property, Object value, Boolean fromStyle, Boolean checkAccess)
    at Xamarin.Forms.BindableObject.SetValue(BindablePropertyKey propertyKey, Object value)
    at Xamarin.Forms.VisualElement.set_Height(Double value)
    at Xamarin.Forms.VisualElement.SetSize(Double width, Double height)
    at Xamarin.Forms.VisualElement.set_Bounds(Rectangle value)
    at Xamarin.Forms.VisualElement.Layout(Rectangle bounds)
    at Xamarin.Forms.Layout.LayoutChildIntoBoundingRegion(VisualElement child, Rectangle region, SizeRequest childSizeRequest)
    at Xamarin.Forms.StackLayout.LayoutChildren(Double x, Double y, Double width, Double height)
    at Xamarin.Forms.Layout.UpdateChildrenLayout()
    at Xamarin.Forms.Layout.OnSizeAllocated(Double width, Double height)
    at Xamarin.Forms.VisualElement.SizeAllocated(Double width, Double height)
    at Xamarin.Forms.Layout.OnChildMeasureInvalidated()
    at Xamarin.Forms.Layout.OnChildMeasureInvalidated(Object sender, EventArgs e)
    at Xamarin.Forms.VisualElement.InvalidateMeasure()
    at Xamarin.Forms.VisualElement.set_IsNativeStateConsistent(Boolean value)
    at Xamarin.Forms.Platform.WinPhone.VisualElementRenderer`2.b__1(Object sender, RoutedEventArgs args)
    at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
    at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)} System.Exception {System.TypeLoadException}

Update clipping on Android

The demo draws big circle that should be clipped in the navigation bar. On Android it is not clipped.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.