android views 1.0.5-alpha - separating out GL and Canvas View for android too
This commit is contained in:
Родитель
0f8e922655
Коммит
a0bfed9ec3
|
@ -0,0 +1,23 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FFMediaToolkit" Version="4.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FluidSharp\FluidSharp.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,118 @@
|
|||
using FFMediaToolkit;
|
||||
using FFMediaToolkit.Encoding;
|
||||
using FFMediaToolkit.Graphics;
|
||||
using FluidSharp.Layouts;
|
||||
using FluidSharp.State;
|
||||
using FluidSharp.Widgets;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FluidSharp.Video.Recorder
|
||||
{
|
||||
|
||||
public class VideoRecorderLayoutSurface : LayoutSurface
|
||||
{
|
||||
|
||||
public CancellationTokenSource CancellationTokenSource;
|
||||
|
||||
|
||||
|
||||
public VideoRecorderLayoutSurface(Device device, MeasureCache measureCache, string FFmpegPath) : base(device, measureCache, null, new VisualState(null, null))
|
||||
{
|
||||
if (FFmpegLoader.FFmpegPath != FFmpegPath)
|
||||
FFmpegLoader.FFmpegPath = FFmpegPath;// @"C:\util\ffmpeg-4.2.1-win-64\bin";
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
CancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
public async Task Run(string fullfilename, SKSize size, float scale, int fps, Func<Widget> makeWidget)
|
||||
{
|
||||
|
||||
|
||||
var MSBetweenFrame = 1000f / fps;
|
||||
|
||||
var w = (((int)(size.Width * scale)) / 4) * 4;
|
||||
var h = (((int)(size.Height * scale)) / 4) * 4;
|
||||
|
||||
var framesize = new System.Drawing.Size(w, h);
|
||||
|
||||
var settings = new VideoEncoderSettings(width: w, height: h, framerate: fps, codec: VideoCodec.H264);
|
||||
settings.EncoderPreset = EncoderPreset.Fast;
|
||||
settings.CRF = 17;
|
||||
|
||||
CancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
var framelen = TimeSpan.FromMilliseconds(MSBetweenFrame);
|
||||
var tframe = DateTime.Now;
|
||||
|
||||
var frameid = 0;
|
||||
using (var outfile = MediaBuilder.CreateContainer(fullfilename).WithVideo(settings).Create())
|
||||
{
|
||||
while (!CancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
|
||||
DrawFrame(outfile, makeWidget, framesize, scale);
|
||||
|
||||
tframe = tframe.Add(framelen);
|
||||
var twait = tframe.Subtract(DateTime.Now);
|
||||
if (twait.TotalMilliseconds > 0)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"waiting {twait.TotalMilliseconds} ms");
|
||||
await Task.Delay(twait);
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"WARNING: producing frame took more than {MSBetweenFrame} ms");
|
||||
}
|
||||
|
||||
frameid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private unsafe void DrawFrame(MediaOutput outfile, Func<Widget> makeWidget, System.Drawing.Size framesize, float scale)
|
||||
{
|
||||
|
||||
var widget = makeWidget();
|
||||
widget = new Scale(scale, widget);
|
||||
|
||||
|
||||
using (var bitmap = new SKBitmap(new SKImageInfo((int)framesize.Width, (int)framesize.Height, SKImageInfo.PlatformColorType, SKAlphaType.Premul)))
|
||||
using (var canvas = new SKCanvas(bitmap))
|
||||
{
|
||||
|
||||
//surface.Canvas.Clear(SKColors.Transparent);
|
||||
canvas.Clear(SKColors.White);
|
||||
|
||||
SetCanvas(canvas);
|
||||
|
||||
Paint(widget, new SKRect(0, 0, framesize.Width, framesize.Height));
|
||||
|
||||
|
||||
// add frame
|
||||
var bpp = 4;
|
||||
var buffersize = bpp * framesize.Width * framesize.Height;
|
||||
|
||||
var span = new Span<byte>(bitmap.GetPixels().ToPointer(), buffersize);
|
||||
var img = new ImageData(span, ImagePixelFormat.Bgra32, framesize);
|
||||
|
||||
outfile.Video.AddFrame(img);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using FluidSharp.State;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace FluidSharp.Views.Android
|
||||
{
|
||||
public abstract class AndroidFluidWidgetView : RelativeLayout
|
||||
{
|
||||
|
||||
public abstract SKSize PlatformScale { get; }
|
||||
public abstract VisualState VisualState { get; }
|
||||
|
||||
protected AndroidFluidWidgetView(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
public void AddOnMainThread(View childview)
|
||||
{
|
||||
|
||||
((Activity)Context).RunOnUiThread(() => AddView(childview));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -51,6 +51,9 @@
|
|||
<Link>FluidWidgetView.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="FluidUIActivity.cs" />
|
||||
<Compile Include="FluidWidgetCanvasView.cs" />
|
||||
<Compile Include="FluidWidgetGLView.cs" />
|
||||
<Compile Include="AndroidFluidWidgetView.cs" />
|
||||
<Compile Include="NativeViewManager.cs" />
|
||||
<Compile Include="NativeViews\FontExtensions.cs" />
|
||||
<Compile Include="NativeViews\KeyboardExtensions.cs" />
|
||||
|
@ -58,6 +61,7 @@
|
|||
<Compile Include="NativeViews\NativeViewExtensions.cs" />
|
||||
<Compile Include="Resources\Resource.designer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SkiaViews.cs" />
|
||||
<Compile Include="SkiaView.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package >
|
||||
<metadata>
|
||||
<id>FluidSharp.Views.Android</id>
|
||||
<version>1.0.4-alpha</version>
|
||||
<version>1.0.5-alpha</version>
|
||||
<title>$title$</title>
|
||||
<authors>Wouter Steenbergen</authors>
|
||||
<owners>My Daily Bits LLC</owners>
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace FluidSharp.Views.Android
|
|||
{
|
||||
|
||||
public readonly IWidgetSource WidgetSource;
|
||||
private FluidWidgetView FluidWidgetView;
|
||||
private AndroidFluidWidgetView FluidWidgetView;
|
||||
|
||||
//private KeyboardTracker KeyboardTracker;
|
||||
//private nfloat OriginalInsetBottom;
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
using FluidSharp.Engine;
|
||||
using FluidSharp.Interop;
|
||||
using FluidSharp.State;
|
||||
using FluidSharp.Widgets;
|
||||
using FluidSharp.Widgets.Native;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
|
||||
#if __FORMS__
|
||||
using FluidSharp.Views.Forms.NativeViews;
|
||||
namespace FluidSharp.Views.Forms
|
||||
#elif __WINDOWSFORMS__
|
||||
using FluidSharp.Views.WindowsForms.NativeViews;
|
||||
using System.Windows.Forms;
|
||||
namespace FluidSharp.Views.WindowsForms
|
||||
#elif __ANDROID__
|
||||
using FluidSharp.Views.Android.NativeViews;
|
||||
using Android.App;
|
||||
using Android.Views;
|
||||
namespace FluidSharp.Views.Android
|
||||
#elif __IOS__
|
||||
using UIKit;
|
||||
using FluidSharp.Views.iOS.NativeViews;
|
||||
namespace FluidSharp.Views.iOS
|
||||
#elif __UWP__
|
||||
namespace FluidSharp.Views.UWP
|
||||
#endif
|
||||
{
|
||||
|
||||
#if __ANDROID__
|
||||
public class FluidWidgetCanvasView : AndroidFluidWidgetView, IFluidWidgetView
|
||||
#else
|
||||
public class FluidWidgetCanvasView : SkiaCanvasView, IFluidWidgetView
|
||||
#endif
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The source of widgets, either overwrite MakeWidget, or set the WidgetSource to implement a custom view
|
||||
/// </summary>
|
||||
public IWidgetSource WidgetSource { get => widgetSource; set { widgetSource = value; SkiaView.InvalidatePaint(); } }
|
||||
private IWidgetSource widgetSource;
|
||||
|
||||
public Device Device;
|
||||
|
||||
private FluidWidgetViewImplementation implementation;
|
||||
public FluidWidgetViewImplementation Implementation
|
||||
{
|
||||
get => implementation;
|
||||
set
|
||||
{
|
||||
if (implementation != null) implementation.Dispose();
|
||||
implementation = value;
|
||||
}
|
||||
}
|
||||
public NativeViewManager NativeViewManager;
|
||||
|
||||
public override VisualState VisualState => Implementation.VisualState;
|
||||
|
||||
/// <summary>
|
||||
/// Set AutoSizeHeight to true if the view should be sized by the (painted) height of the widgets.
|
||||
/// The default is false.
|
||||
/// </summary>
|
||||
public bool AutoSizeHeight { get; set; }
|
||||
private float LastPaintWidth = -1;
|
||||
private float LastHeightRequest = -1;
|
||||
|
||||
#if __ANDROID__
|
||||
|
||||
private SkiaCanvasView SkiaView;
|
||||
public override SKSize PlatformScale => SkiaView.PlatformScale;
|
||||
|
||||
public FluidWidgetCanvasView(global::Android.Content.Context context) : base(context)
|
||||
{
|
||||
|
||||
SkiaView = new SkiaCanvasView(context);
|
||||
var fillparams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent);
|
||||
AddView(SkiaView, fillparams);
|
||||
|
||||
#else
|
||||
|
||||
private SkiaCanvasView SkiaView => this;
|
||||
|
||||
public FluidWidgetCanvasView()
|
||||
{
|
||||
#endif
|
||||
|
||||
Device = new Device();
|
||||
|
||||
#if __FORMS__
|
||||
Device.FlowDirection = Xamarin.Forms.Device.FlowDirection == Xamarin.Forms.FlowDirection.RightToLeft ? SkiaSharp.TextBlocks.Enum.FlowDirection.RightToLeft : SkiaSharp.TextBlocks.Enum.FlowDirection.LeftToRight;
|
||||
#endif
|
||||
|
||||
NativeViewManager = new NativeViewManager(this);
|
||||
|
||||
Implementation = new FluidWidgetViewImplementation(SkiaView, this, Device);
|
||||
|
||||
RegisterNativeViews();
|
||||
|
||||
}
|
||||
|
||||
#if __ANDROID__
|
||||
public FluidWidgetCanvasView(global::Android.Content.Context context, bool CreatesOwnImplementation) : base(context)
|
||||
#else
|
||||
protected FluidWidgetCanvasView(bool CreatesOwnImplementation)
|
||||
#endif
|
||||
{
|
||||
if (!CreatesOwnImplementation) throw new ArgumentOutOfRangeException(nameof(CreatesOwnImplementation));
|
||||
}
|
||||
|
||||
protected void RegisterNativeViews()
|
||||
{
|
||||
#if __IOS__
|
||||
NativeViewManager.RegisterNativeView<NativeTextboxWidget, UIView>(
|
||||
(w, c) => ((INativeTextboxImpl)c).Context.Equals(w.Context),
|
||||
(w) => w.Keyboard == Keyboard.MultiLine ? (UIView)
|
||||
new NativeMultiLineTextboxImpl(VisualState.RequestRedraw) { Context = w.Context } :
|
||||
new NativeSingleLineTextboxImpl(VisualState.RequestRedraw) { Context = w.Context }
|
||||
#else
|
||||
NativeViewManager.RegisterNativeView<NativeTextboxWidget, NativeTextboxImpl>(
|
||||
(w, c) => c.Context.Equals(w.Context),
|
||||
#if __ANDROID__
|
||||
(w) => new NativeTextboxImpl(Context, VisualState.RequestRedraw) { Context = w.Context }
|
||||
#else
|
||||
(w) => new NativeTextboxImpl(VisualState.RequestRedraw) { Context = w.Context }
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
public INativeViewManager GetNativeViewManager() => NativeViewManager;
|
||||
|
||||
/// <summary>
|
||||
/// Either overwrite this method or set WidgetSource to implement a custom view
|
||||
/// </summary>
|
||||
public virtual Widget MakeWidget(VisualState visualState)
|
||||
{
|
||||
if (WidgetSource == null)
|
||||
return Rectangle.Fill(SKColors.Teal);
|
||||
else
|
||||
return WidgetSource.MakeWidget(visualState);
|
||||
}
|
||||
|
||||
public void SetHeight(float height)
|
||||
{
|
||||
// Maximum height: screen / device size
|
||||
#if __FORMS__
|
||||
#elif __WINDOWSFORMS__
|
||||
height = Math.Min(Height, Screen.FromControl(this).WorkingArea.Height);
|
||||
#elif __ANDROID__
|
||||
#elif __IOS__
|
||||
#elif __UWP__
|
||||
#endif
|
||||
|
||||
// Minimum height: 10
|
||||
height = Math.Max(height, 10);
|
||||
|
||||
// Apply height
|
||||
#if __FORMS__
|
||||
if (this.Height < height - 5 || this.Height > height + 5) InvalidateMeasure();
|
||||
#elif __WINDOWSFORMS__
|
||||
this.Height = (int)height;
|
||||
#elif __ANDROID__
|
||||
#elif __IOS__
|
||||
#elif __UWP__
|
||||
#endif
|
||||
}
|
||||
|
||||
public virtual SKColor GetBackgroundColor(VisualState visualState)
|
||||
{
|
||||
if (widgetSource is IBackgroundColorSource backgroundColorSource) return backgroundColorSource.GetBackgroundColor(visualState);
|
||||
return default;
|
||||
}
|
||||
|
||||
|
||||
#if __FORMS__
|
||||
|
||||
protected override void OnSizeAllocated(double width, double height)
|
||||
{
|
||||
base.OnSizeAllocated(width, height);
|
||||
LastPaintWidth = (float)Width;
|
||||
}
|
||||
|
||||
protected override void InvalidateMeasure()
|
||||
{
|
||||
base.InvalidateMeasure();
|
||||
InvalidatePaint();
|
||||
}
|
||||
|
||||
protected override void OnBindingContextChanged()
|
||||
{
|
||||
base.OnBindingContextChanged();
|
||||
if (BindingContext == null)
|
||||
Implementation.Dispose();
|
||||
}
|
||||
|
||||
protected override Xamarin.Forms.SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
|
||||
{
|
||||
|
||||
if (Width == LastPaintWidth && LastHeightRequest > -1)
|
||||
return new Xamarin.Forms.SizeRequest(new Xamarin.Forms.Size(LastPaintWidth, LastHeightRequest));
|
||||
|
||||
var request = Implementation.Measure(new SKSize((float)widthConstraint, (float)heightConstraint));
|
||||
System.Diagnostics.Debug.WriteLine($"LinkTileView Measured: {request} ({widthConstraint}, {heightConstraint}) ");
|
||||
|
||||
if (float.IsInfinity(request.Width) || float.IsInfinity(request.Height))
|
||||
return base.OnMeasure(widthConstraint, heightConstraint);
|
||||
|
||||
return new Xamarin.Forms.SizeRequest(new Xamarin.Forms.Size(request.Width, request.Height));
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if __WINDOWSFORMS__
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (disposing)
|
||||
Implementation.Dispose();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
using FluidSharp.Engine;
|
||||
using FluidSharp.Interop;
|
||||
using FluidSharp.State;
|
||||
using FluidSharp.Widgets;
|
||||
using FluidSharp.Widgets.Native;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
|
||||
#if __FORMS__
|
||||
using FluidSharp.Views.Forms.NativeViews;
|
||||
namespace FluidSharp.Views.Forms
|
||||
#elif __WINDOWSFORMS__
|
||||
using FluidSharp.Views.WindowsForms.NativeViews;
|
||||
using System.Windows.Forms;
|
||||
namespace FluidSharp.Views.WindowsForms
|
||||
#elif __ANDROID__
|
||||
using FluidSharp.Views.Android.NativeViews;
|
||||
using Android.App;
|
||||
using Android.Views;
|
||||
namespace FluidSharp.Views.Android
|
||||
#elif __IOS__
|
||||
using UIKit;
|
||||
using FluidSharp.Views.iOS.NativeViews;
|
||||
namespace FluidSharp.Views.iOS
|
||||
#elif __UWP__
|
||||
namespace FluidSharp.Views.UWP
|
||||
#endif
|
||||
{
|
||||
|
||||
#if __ANDROID__
|
||||
public class FluidWidgetGLView : AndroidFluidWidgetView, IFluidWidgetView
|
||||
#else
|
||||
public class FluidWidgetGLView : SkiaGLView, IFluidWidgetView
|
||||
#endif
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The source of widgets, either overwrite MakeWidget, or set the WidgetSource to implement a custom view
|
||||
/// </summary>
|
||||
public IWidgetSource WidgetSource { get => widgetSource; set { widgetSource = value; SkiaView.InvalidatePaint(); } }
|
||||
private IWidgetSource widgetSource;
|
||||
|
||||
public Device Device;
|
||||
|
||||
private FluidWidgetViewImplementation implementation;
|
||||
public FluidWidgetViewImplementation Implementation
|
||||
{
|
||||
get => implementation;
|
||||
set
|
||||
{
|
||||
if (implementation != null) implementation.Dispose();
|
||||
implementation = value;
|
||||
}
|
||||
}
|
||||
public NativeViewManager NativeViewManager;
|
||||
|
||||
public override VisualState VisualState => Implementation.VisualState;
|
||||
|
||||
/// <summary>
|
||||
/// Set AutoSizeHeight to true if the view should be sized by the (painted) height of the widgets.
|
||||
/// The default is false.
|
||||
/// </summary>
|
||||
public bool AutoSizeHeight { get; set; }
|
||||
private float LastPaintWidth = -1;
|
||||
private float LastHeightRequest = -1;
|
||||
|
||||
#if __ANDROID__
|
||||
|
||||
private SkiaGLView SkiaView;
|
||||
public override SKSize PlatformScale => SkiaView.PlatformScale;
|
||||
|
||||
public FluidWidgetGLView(global::Android.Content.Context context) : base(context)
|
||||
{
|
||||
|
||||
SkiaView = new SkiaGLView(context);
|
||||
var fillparams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent);
|
||||
AddView(SkiaView, fillparams);
|
||||
|
||||
#else
|
||||
|
||||
private SkiaGLView SkiaView => this;
|
||||
|
||||
public FluidWidgetGLView()
|
||||
{
|
||||
#endif
|
||||
|
||||
Device = new Device();
|
||||
|
||||
#if __FORMS__
|
||||
Device.FlowDirection = Xamarin.Forms.Device.FlowDirection == Xamarin.Forms.FlowDirection.RightToLeft ? SkiaSharp.TextBlocks.Enum.FlowDirection.RightToLeft : SkiaSharp.TextBlocks.Enum.FlowDirection.LeftToRight;
|
||||
#endif
|
||||
|
||||
NativeViewManager = new NativeViewManager(this);
|
||||
|
||||
Implementation = new FluidWidgetViewImplementation(SkiaView, this, Device);
|
||||
|
||||
RegisterNativeViews();
|
||||
|
||||
}
|
||||
|
||||
#if __ANDROID__
|
||||
public FluidWidgetGLView(global::Android.Content.Context context, bool CreatesOwnImplementation) : base(context)
|
||||
#else
|
||||
protected FluidWidgetGLView(bool CreatesOwnImplementation)
|
||||
#endif
|
||||
{
|
||||
if (!CreatesOwnImplementation) throw new ArgumentOutOfRangeException(nameof(CreatesOwnImplementation));
|
||||
}
|
||||
|
||||
protected void RegisterNativeViews()
|
||||
{
|
||||
#if __IOS__
|
||||
NativeViewManager.RegisterNativeView<NativeTextboxWidget, UIView>(
|
||||
(w, c) => ((INativeTextboxImpl)c).Context.Equals(w.Context),
|
||||
(w) => w.Keyboard == Keyboard.MultiLine ? (UIView)
|
||||
new NativeMultiLineTextboxImpl(VisualState.RequestRedraw) { Context = w.Context } :
|
||||
new NativeSingleLineTextboxImpl(VisualState.RequestRedraw) { Context = w.Context }
|
||||
#else
|
||||
NativeViewManager.RegisterNativeView<NativeTextboxWidget, NativeTextboxImpl>(
|
||||
(w, c) => c.Context.Equals(w.Context),
|
||||
#if __ANDROID__
|
||||
(w) => new NativeTextboxImpl(Context, VisualState.RequestRedraw) { Context = w.Context }
|
||||
#else
|
||||
(w) => new NativeTextboxImpl(VisualState.RequestRedraw) { Context = w.Context }
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
public INativeViewManager GetNativeViewManager() => NativeViewManager;
|
||||
|
||||
/// <summary>
|
||||
/// Either overwrite this method or set WidgetSource to implement a custom view
|
||||
/// </summary>
|
||||
public virtual Widget MakeWidget(VisualState visualState)
|
||||
{
|
||||
if (WidgetSource == null)
|
||||
return Rectangle.Fill(SKColors.Teal);
|
||||
else
|
||||
return WidgetSource.MakeWidget(visualState);
|
||||
}
|
||||
|
||||
public void SetHeight(float height)
|
||||
{
|
||||
// Maximum height: screen / device size
|
||||
#if __FORMS__
|
||||
#elif __WINDOWSFORMS__
|
||||
height = Math.Min(Height, Screen.FromControl(this).WorkingArea.Height);
|
||||
#elif __ANDROID__
|
||||
#elif __IOS__
|
||||
#elif __UWP__
|
||||
#endif
|
||||
|
||||
// Minimum height: 10
|
||||
height = Math.Max(height, 10);
|
||||
|
||||
// Apply height
|
||||
#if __FORMS__
|
||||
if (this.Height < height - 5 || this.Height > height + 5) InvalidateMeasure();
|
||||
#elif __WINDOWSFORMS__
|
||||
this.Height = (int)height;
|
||||
#elif __ANDROID__
|
||||
#elif __IOS__
|
||||
#elif __UWP__
|
||||
#endif
|
||||
}
|
||||
|
||||
public virtual SKColor GetBackgroundColor(VisualState visualState)
|
||||
{
|
||||
if (widgetSource is IBackgroundColorSource backgroundColorSource) return backgroundColorSource.GetBackgroundColor(visualState);
|
||||
return default;
|
||||
}
|
||||
|
||||
|
||||
#if __FORMS__
|
||||
|
||||
protected override void OnSizeAllocated(double width, double height)
|
||||
{
|
||||
base.OnSizeAllocated(width, height);
|
||||
LastPaintWidth = (float)Width;
|
||||
}
|
||||
|
||||
protected override void InvalidateMeasure()
|
||||
{
|
||||
base.InvalidateMeasure();
|
||||
InvalidatePaint();
|
||||
}
|
||||
|
||||
protected override void OnBindingContextChanged()
|
||||
{
|
||||
base.OnBindingContextChanged();
|
||||
if (BindingContext == null)
|
||||
Implementation.Dispose();
|
||||
}
|
||||
|
||||
protected override Xamarin.Forms.SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
|
||||
{
|
||||
|
||||
if (Width == LastPaintWidth && LastHeightRequest > -1)
|
||||
return new Xamarin.Forms.SizeRequest(new Xamarin.Forms.Size(LastPaintWidth, LastHeightRequest));
|
||||
|
||||
var request = Implementation.Measure(new SKSize((float)widthConstraint, (float)heightConstraint));
|
||||
System.Diagnostics.Debug.WriteLine($"LinkTileView Measured: {request} ({widthConstraint}, {heightConstraint}) ");
|
||||
|
||||
if (float.IsInfinity(request.Width) || float.IsInfinity(request.Height))
|
||||
return base.OnMeasure(widthConstraint, heightConstraint);
|
||||
|
||||
return new Xamarin.Forms.SizeRequest(new Xamarin.Forms.Size(request.Width, request.Height));
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if __WINDOWSFORMS__
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (disposing)
|
||||
Implementation.Dispose();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -21,9 +21,9 @@ namespace FluidSharp.Views.Android
|
|||
{
|
||||
|
||||
// public View View;
|
||||
public FluidWidgetView ViewGroup;
|
||||
public AndroidFluidWidgetView ViewGroup;
|
||||
|
||||
public NativeViewManager(FluidWidgetView viewGroup)
|
||||
public NativeViewManager(AndroidFluidWidgetView viewGroup)
|
||||
{
|
||||
ViewGroup = viewGroup;
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ namespace FluidSharp.Views.Android
|
|||
for (int i = 0; i < ViewGroup.ChildCount; i++)
|
||||
{
|
||||
var child = ViewGroup.GetChildAt(i);
|
||||
if (!(child is SkiaView))
|
||||
if (!(child is SkiaGLView || child is SkiaCanvasView))
|
||||
yield return child;
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ namespace FluidSharp.Views.Android
|
|||
nativeImpl.SetBounds(targetbounds);
|
||||
nativeImpl.UpdateControl(nativeViewWidget, rect, original);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#define USEGL
|
||||
#if false
|
||||
#define USEGL
|
||||
using Android.App;
|
||||
using Android.Views;
|
||||
using FluidSharp.Touch;
|
||||
|
@ -277,3 +278,4 @@ namespace FluidSharp.Views.Android
|
|||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,507 @@
|
|||
using Android.App;
|
||||
using Android.Views;
|
||||
using FluidSharp.Touch;
|
||||
using SkiaSharp;
|
||||
using SkiaSharp.Views.Android;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AView = Android.Views.View;
|
||||
|
||||
namespace FluidSharp.Views.Android
|
||||
{
|
||||
public class SkiaGLView : SKGLTextureView, ISkiaView
|
||||
{
|
||||
|
||||
float ISkiaView.Width => Width / PlatformScale.Width;
|
||||
float ISkiaView.Height => Height / PlatformScale.Height;
|
||||
public SKSize PlatformScale;
|
||||
|
||||
SKSize GetSize() => new SKSize(Width / PlatformScale.Width, Height / PlatformScale.Height);
|
||||
SKPoint ScalePoint(SKPoint point) => new SKPoint(point.X / PlatformScale.Width, point.Y / PlatformScale.Height);
|
||||
|
||||
public event EventHandler<PaintSurfaceEventArgs> PaintViewSurface;
|
||||
public new event EventHandler<TouchActionEventArgs> Touch;
|
||||
|
||||
public void InvalidatePaint()
|
||||
{
|
||||
((Activity)Context).RunOnUiThread(() => Invalidate());
|
||||
}
|
||||
|
||||
public SkiaGLView(global::Android.Content.Context context) : base(context)
|
||||
{
|
||||
PlatformScale = new SKSize(Resources.DisplayMetrics.Xdpi / 140, Resources.DisplayMetrics.Ydpi / 140);
|
||||
}
|
||||
|
||||
|
||||
protected override void OnPaintSurface(SKPaintGLSurfaceEventArgs e)
|
||||
{
|
||||
|
||||
var canvas = e.Surface.Canvas;
|
||||
// Make sure the canvas is drawn using pixel coordinates (but still high res):
|
||||
|
||||
// var factor = (float)MathF.Round(e.BackendRenderTarget.Width / w * 4) / 4;
|
||||
var platformzoom = SKMatrix.CreateScale(PlatformScale.Width, PlatformScale.Height);
|
||||
//var platformzoom = SKMatrix.CreateScale(factor, factor);
|
||||
canvas.Concat(ref platformzoom);
|
||||
|
||||
var w = ((ISkiaView)this).Width;
|
||||
var h = ((ISkiaView)this).Height;
|
||||
|
||||
PaintViewSurface?.Invoke(this, new PaintSurfaceEventArgs(canvas, w, h, e.Surface, default));
|
||||
|
||||
}
|
||||
|
||||
private void Touchrecognizer_Touch(object sender, TouchActionEventArgs e)
|
||||
{
|
||||
//System.Diagnostics.Debug.WriteLine("touch");
|
||||
Touch?.Invoke(this, e);
|
||||
}
|
||||
|
||||
//protected override void Dispose(bool disposing)
|
||||
//{
|
||||
// // detach all events before disposing
|
||||
// var controller = (ISKCanvasViewController)Element;
|
||||
// if (controller != null)
|
||||
// {
|
||||
// controller.SurfaceInvalidated -= OnSurfaceInvalidated;
|
||||
// controller.GetCanvasSize -= OnGetCanvasSize;
|
||||
// }
|
||||
|
||||
// var control = Control;
|
||||
// if (control != null)
|
||||
// {
|
||||
// control.PaintSurface -= OnPaintSurface;
|
||||
// }
|
||||
|
||||
// // detach, regardless of state
|
||||
// touchHandler.Detach(control);
|
||||
|
||||
// base.Dispose(disposing);
|
||||
//}
|
||||
|
||||
bool capture;
|
||||
int[] twoIntArray = new int[2];
|
||||
|
||||
const bool Capture = true;
|
||||
|
||||
public override bool OnTouchEvent(MotionEvent e)
|
||||
{
|
||||
// return base.OnTouchEvent(e);
|
||||
//}
|
||||
|
||||
//private void OnTouch(object sender, TouchEventArgs args)
|
||||
//{
|
||||
|
||||
// // Two object common to all the events
|
||||
// var senderView = sender as global::AView;
|
||||
// MotionEvent motionEvent = args.Event;
|
||||
|
||||
var senderView = this;
|
||||
var motionEvent = e;
|
||||
|
||||
// Get the pointer index
|
||||
int pointerIndex = motionEvent.ActionIndex;
|
||||
|
||||
// Get the id that identifies a finger over the course of its progress
|
||||
int id = motionEvent.GetPointerId(pointerIndex);
|
||||
|
||||
senderView.GetLocationOnScreen(twoIntArray);
|
||||
|
||||
var pointinview = ScalePoint(new SKPoint(motionEvent.GetX(pointerIndex), motionEvent.GetY(pointerIndex)));
|
||||
var pointondevice = ScalePoint(new SKPoint(twoIntArray[0] + pointinview.X,
|
||||
twoIntArray[1] + pointinview.Y));
|
||||
|
||||
|
||||
// Use ActionMasked here rather than Action to reduce the number of possibilities
|
||||
switch (motionEvent.ActionMasked)
|
||||
{
|
||||
case MotionEventActions.Down:
|
||||
case MotionEventActions.PointerDown:
|
||||
FireEvent(id, TouchActionType.Pressed, pointondevice, pointinview, true);
|
||||
|
||||
capture = Capture;
|
||||
break;
|
||||
|
||||
case MotionEventActions.Move:
|
||||
// Multiple Move events are bundled, so handle them in a loop
|
||||
for (pointerIndex = 0; pointerIndex < motionEvent.PointerCount; pointerIndex++)
|
||||
{
|
||||
id = motionEvent.GetPointerId(pointerIndex);
|
||||
|
||||
if (capture)
|
||||
{
|
||||
senderView.GetLocationOnScreen(twoIntArray);
|
||||
|
||||
pointinview = ScalePoint(new SKPoint(motionEvent.GetX(pointerIndex), motionEvent.GetY(pointerIndex)));
|
||||
pointondevice = ScalePoint(new SKPoint(twoIntArray[0] + pointinview.X,
|
||||
twoIntArray[1] + pointinview.Y));
|
||||
|
||||
FireEvent(id, TouchActionType.Moved, pointondevice, pointinview, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
//CheckForBoundaryHop(id, pointondevice);
|
||||
FireEvent(id, TouchActionType.Moved, pointondevice, pointinview, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEventActions.Up:
|
||||
case MotionEventActions.Pointer1Up:
|
||||
if (capture)
|
||||
{
|
||||
FireEvent(id, TouchActionType.Released, pointondevice, pointinview, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
//CheckForBoundaryHop(id, pointondevice);
|
||||
FireEvent(id, TouchActionType.Released, pointondevice, pointinview, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEventActions.Cancel:
|
||||
if (capture)
|
||||
{
|
||||
FireEvent(id, TouchActionType.Cancelled, pointondevice, pointinview, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
FireEvent(id, TouchActionType.Cancelled, pointondevice, pointinview, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
void FireEvent(long id, TouchActionType actionType, SKPoint pointondevice, SKPoint pointinview, bool isInContact)
|
||||
{
|
||||
|
||||
//var rootview = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
|
||||
//var ondevice = touch.LocationInView(rootview);
|
||||
//var pointondevice = new SKPoint((float)ondevice.X, (float)ondevice.Y);
|
||||
|
||||
// Convert touch location to Xamarin.Forms Point value
|
||||
//var cgPoint = touch.LocationInView(recognizer.View);
|
||||
//var xfPoint = new SKPoint((float)cgPoint.X, (float)cgPoint.Y);
|
||||
|
||||
//var viewsize = recognizer.View.Bounds.Size;
|
||||
// var cgsize = touch.LocationInView(recognizer.View);
|
||||
//var size = new SKSize(Width, Height);
|
||||
var size = GetSize();
|
||||
|
||||
System.Diagnostics.Debug.WriteLine($"Touch {actionType} {pointondevice}");
|
||||
|
||||
|
||||
Touch?.Invoke(this, new TouchActionEventArgs(id, actionType, pointondevice, pointinview, size, isInContact));
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//void CheckForBoundaryHop(int id, Point pointerLocation)
|
||||
//{
|
||||
// TouchEffect touchEffectHit = null;
|
||||
|
||||
// foreach (AView view in viewDictionary.Keys)
|
||||
// {
|
||||
// // Get the view rectangle
|
||||
// try
|
||||
// {
|
||||
// view.GetLocationOnScreen(twoIntArray);
|
||||
// }
|
||||
// catch // System.ObjectDisposedException: Cannot access a disposed object.
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// Rectangle viewRect = new Rectangle(twoIntArray[0], twoIntArray[1], view.Width, view.Height);
|
||||
|
||||
// if (viewRect.Contains(pointerLocation))
|
||||
// {
|
||||
// touchEffectHit = viewDictionary[view];
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (touchEffectHit != idToEffectDictionary[id])
|
||||
// {
|
||||
// if (idToEffectDictionary[id] != null)
|
||||
// {
|
||||
// FireEvent(idToEffectDictionary[id], id, TouchActionType.Exited, pointerLocation, true);
|
||||
// }
|
||||
// if (touchEffectHit != null)
|
||||
// {
|
||||
// FireEvent(touchEffectHit, id, TouchActionType.Entered, pointerLocation, true);
|
||||
// }
|
||||
// idToEffectDictionary[id] = touchEffectHit;
|
||||
// }
|
||||
//}
|
||||
|
||||
//void FireEvent(TouchEffect touchEffect, int id, TouchActionType actionType, Point pointerLocation, bool isInContact)
|
||||
//{
|
||||
// // Get the method to call for firing events
|
||||
// Action<Element, TouchActionEventArgs> onTouchAction = touchEffect.libTouchEffect.OnTouchAction;
|
||||
|
||||
// // Get the location of the pointer within the view
|
||||
// touchEffect.view.GetLocationOnScreen(twoIntArray);
|
||||
// double x = pointerLocation.X - twoIntArray[0];
|
||||
// double y = pointerLocation.Y - twoIntArray[1];
|
||||
// Point point = new Point(fromPixels(x), fromPixels(y));
|
||||
|
||||
// // Call the method
|
||||
// onTouchAction(touchEffect.formsElement,
|
||||
// new TouchActionEventArgs(id, actionType, point, isInContact));
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class SkiaCanvasView : SKCanvasView, ISkiaView
|
||||
{
|
||||
|
||||
float ISkiaView.Width => Width / PlatformScale.Width;
|
||||
float ISkiaView.Height => Height / PlatformScale.Height;
|
||||
public SKSize PlatformScale;
|
||||
|
||||
SKSize GetSize() => new SKSize(Width / PlatformScale.Width, Height / PlatformScale.Height);
|
||||
SKPoint ScalePoint(SKPoint point) => new SKPoint(point.X / PlatformScale.Width, point.Y / PlatformScale.Height);
|
||||
|
||||
public event EventHandler<PaintSurfaceEventArgs> PaintViewSurface;
|
||||
public new event EventHandler<TouchActionEventArgs> Touch;
|
||||
|
||||
public void InvalidatePaint()
|
||||
{
|
||||
((Activity)Context).RunOnUiThread(() => Invalidate());
|
||||
}
|
||||
|
||||
public SkiaCanvasView(global::Android.Content.Context context) : base(context)
|
||||
{
|
||||
|
||||
PlatformScale = new SKSize(Resources.DisplayMetrics.Xdpi / 140, Resources.DisplayMetrics.Ydpi / 140);
|
||||
|
||||
|
||||
this.PaintSurface += SkiaControl_PaintSurface;
|
||||
}
|
||||
|
||||
|
||||
private void SkiaControl_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
|
||||
{
|
||||
|
||||
var canvas = e.Surface.Canvas;
|
||||
// Make sure the canvas is drawn using pixel coordinates (but still high res):
|
||||
|
||||
|
||||
// var factor = (float)MathF.Round(e.Info.Width / w * 4) / 4;
|
||||
var platformzoom = SKMatrix.CreateScale(PlatformScale.Width, PlatformScale.Height);
|
||||
//var platformzoom = SKMatrix.CreateScale(factor, factor);
|
||||
canvas.Concat(ref platformzoom);
|
||||
|
||||
var w = ((ISkiaView)this).Width;
|
||||
var h = ((ISkiaView)this).Height;
|
||||
|
||||
PaintViewSurface?.Invoke(this, new PaintSurfaceEventArgs(canvas, w, h, e.Surface, default));
|
||||
|
||||
}
|
||||
|
||||
private void Touchrecognizer_Touch(object sender, TouchActionEventArgs e)
|
||||
{
|
||||
//System.Diagnostics.Debug.WriteLine("touch");
|
||||
Touch?.Invoke(this, e);
|
||||
}
|
||||
|
||||
//protected override void Dispose(bool disposing)
|
||||
//{
|
||||
// // detach all events before disposing
|
||||
// var controller = (ISKCanvasViewController)Element;
|
||||
// if (controller != null)
|
||||
// {
|
||||
// controller.SurfaceInvalidated -= OnSurfaceInvalidated;
|
||||
// controller.GetCanvasSize -= OnGetCanvasSize;
|
||||
// }
|
||||
|
||||
// var control = Control;
|
||||
// if (control != null)
|
||||
// {
|
||||
// control.PaintSurface -= OnPaintSurface;
|
||||
// }
|
||||
|
||||
// // detach, regardless of state
|
||||
// touchHandler.Detach(control);
|
||||
|
||||
// base.Dispose(disposing);
|
||||
//}
|
||||
|
||||
bool capture;
|
||||
int[] twoIntArray = new int[2];
|
||||
|
||||
const bool Capture = true;
|
||||
|
||||
public override bool OnTouchEvent(MotionEvent e)
|
||||
{
|
||||
// return base.OnTouchEvent(e);
|
||||
//}
|
||||
|
||||
//private void OnTouch(object sender, TouchEventArgs args)
|
||||
//{
|
||||
|
||||
// // Two object common to all the events
|
||||
// var senderView = sender as global::AView;
|
||||
// MotionEvent motionEvent = args.Event;
|
||||
|
||||
var senderView = this;
|
||||
var motionEvent = e;
|
||||
|
||||
// Get the pointer index
|
||||
int pointerIndex = motionEvent.ActionIndex;
|
||||
|
||||
// Get the id that identifies a finger over the course of its progress
|
||||
int id = motionEvent.GetPointerId(pointerIndex);
|
||||
|
||||
senderView.GetLocationOnScreen(twoIntArray);
|
||||
|
||||
var pointinview = ScalePoint(new SKPoint(motionEvent.GetX(pointerIndex), motionEvent.GetY(pointerIndex)));
|
||||
var pointondevice = ScalePoint(new SKPoint(twoIntArray[0] + pointinview.X,
|
||||
twoIntArray[1] + pointinview.Y));
|
||||
|
||||
|
||||
// Use ActionMasked here rather than Action to reduce the number of possibilities
|
||||
switch (motionEvent.ActionMasked)
|
||||
{
|
||||
case MotionEventActions.Down:
|
||||
case MotionEventActions.PointerDown:
|
||||
FireEvent(id, TouchActionType.Pressed, pointondevice, pointinview, true);
|
||||
|
||||
capture = Capture;
|
||||
break;
|
||||
|
||||
case MotionEventActions.Move:
|
||||
// Multiple Move events are bundled, so handle them in a loop
|
||||
for (pointerIndex = 0; pointerIndex < motionEvent.PointerCount; pointerIndex++)
|
||||
{
|
||||
id = motionEvent.GetPointerId(pointerIndex);
|
||||
|
||||
if (capture)
|
||||
{
|
||||
senderView.GetLocationOnScreen(twoIntArray);
|
||||
|
||||
pointinview = ScalePoint(new SKPoint(motionEvent.GetX(pointerIndex), motionEvent.GetY(pointerIndex)));
|
||||
pointondevice = ScalePoint(new SKPoint(twoIntArray[0] + pointinview.X,
|
||||
twoIntArray[1] + pointinview.Y));
|
||||
|
||||
FireEvent(id, TouchActionType.Moved, pointondevice, pointinview, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
//CheckForBoundaryHop(id, pointondevice);
|
||||
FireEvent(id, TouchActionType.Moved, pointondevice, pointinview, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEventActions.Up:
|
||||
case MotionEventActions.Pointer1Up:
|
||||
if (capture)
|
||||
{
|
||||
FireEvent(id, TouchActionType.Released, pointondevice, pointinview, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
//CheckForBoundaryHop(id, pointondevice);
|
||||
FireEvent(id, TouchActionType.Released, pointondevice, pointinview, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEventActions.Cancel:
|
||||
if (capture)
|
||||
{
|
||||
FireEvent(id, TouchActionType.Cancelled, pointondevice, pointinview, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
FireEvent(id, TouchActionType.Cancelled, pointondevice, pointinview, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
void FireEvent(long id, TouchActionType actionType, SKPoint pointondevice, SKPoint pointinview, bool isInContact)
|
||||
{
|
||||
|
||||
//var rootview = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
|
||||
//var ondevice = touch.LocationInView(rootview);
|
||||
//var pointondevice = new SKPoint((float)ondevice.X, (float)ondevice.Y);
|
||||
|
||||
// Convert touch location to Xamarin.Forms Point value
|
||||
//var cgPoint = touch.LocationInView(recognizer.View);
|
||||
//var xfPoint = new SKPoint((float)cgPoint.X, (float)cgPoint.Y);
|
||||
|
||||
//var viewsize = recognizer.View.Bounds.Size;
|
||||
// var cgsize = touch.LocationInView(recognizer.View);
|
||||
//var size = new SKSize(Width, Height);
|
||||
var size = GetSize();
|
||||
|
||||
System.Diagnostics.Debug.WriteLine($"Touch {actionType} {pointondevice}");
|
||||
|
||||
|
||||
Touch?.Invoke(this, new TouchActionEventArgs(id, actionType, pointondevice, pointinview, size, isInContact));
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//void CheckForBoundaryHop(int id, Point pointerLocation)
|
||||
//{
|
||||
// TouchEffect touchEffectHit = null;
|
||||
|
||||
// foreach (AView view in viewDictionary.Keys)
|
||||
// {
|
||||
// // Get the view rectangle
|
||||
// try
|
||||
// {
|
||||
// view.GetLocationOnScreen(twoIntArray);
|
||||
// }
|
||||
// catch // System.ObjectDisposedException: Cannot access a disposed object.
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// Rectangle viewRect = new Rectangle(twoIntArray[0], twoIntArray[1], view.Width, view.Height);
|
||||
|
||||
// if (viewRect.Contains(pointerLocation))
|
||||
// {
|
||||
// touchEffectHit = viewDictionary[view];
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (touchEffectHit != idToEffectDictionary[id])
|
||||
// {
|
||||
// if (idToEffectDictionary[id] != null)
|
||||
// {
|
||||
// FireEvent(idToEffectDictionary[id], id, TouchActionType.Exited, pointerLocation, true);
|
||||
// }
|
||||
// if (touchEffectHit != null)
|
||||
// {
|
||||
// FireEvent(touchEffectHit, id, TouchActionType.Entered, pointerLocation, true);
|
||||
// }
|
||||
// idToEffectDictionary[id] = touchEffectHit;
|
||||
// }
|
||||
//}
|
||||
|
||||
//void FireEvent(TouchEffect touchEffect, int id, TouchActionType actionType, Point pointerLocation, bool isInContact)
|
||||
//{
|
||||
// // Get the method to call for firing events
|
||||
// Action<Element, TouchActionEventArgs> onTouchAction = touchEffect.libTouchEffect.OnTouchAction;
|
||||
|
||||
// // Get the location of the pointer within the view
|
||||
// touchEffect.view.GetLocationOnScreen(twoIntArray);
|
||||
// double x = pointerLocation.X - twoIntArray[0];
|
||||
// double y = pointerLocation.Y - twoIntArray[1];
|
||||
// Point point = new Point(fromPixels(x), fromPixels(y));
|
||||
|
||||
// // Call the method
|
||||
// onTouchAction(touchEffect.formsElement,
|
||||
// new TouchActionEventArgs(id, actionType, point, isInContact));
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
#if !__IOS__
|
||||
#if !__IOS__ && !__ANDROID__
|
||||
|
||||
using FluidSharp.Engine;
|
||||
using FluidSharp.Interop;
|
||||
|
|
Загрузка…
Ссылка в новой задаче