Improved Android and iOS gesture (fixed touch collision with CollectionView, etc)

This commit is contained in:
Javier Suárez Ruiz 2020-05-24 13:13:01 +02:00
Родитель 81b8a9325d
Коммит 77a5c07065
18 изменённых файлов: 11965 добавлений и 99 удалений

2620
src/TabView.Sample.Android/Resources/Resource.designer.cs сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -108,6 +108,10 @@
<Project>{08B92D62-4595-4ACF-B6ED-743B52892E72}</Project>
<Name>TabView.Sample</Name>
</ProjectReference>
<ProjectReference Include="..\Xamarin.Forms.TabView.Android\Xamarin.Forms.TabView.Android.csproj">
<Project>{335288B7-AA6F-487C-B4AA-88B9E3261BD5}</Project>
<Name>Xamarin.Forms.TabView.Android</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<AndroidAsset Include="Assets\materialdesignicons-webfont.ttf" />

Просмотреть файл

@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using Foundation;
using UIKit;
using Xamarin.Forms.TabView.iOS;
namespace TabView.Sample.iOS
{
@ -11,7 +8,7 @@ namespace TabView.Sample.iOS
// User Interface of the application, as well as listening (and optionally responding) to
// application events from iOS.
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
public partial class AppDelegate : Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this
@ -22,7 +19,8 @@ namespace TabView.Sample.iOS
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
CarouselViewRenderer.Preserve();
Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);

Просмотреть файл

@ -131,6 +131,10 @@
<Project>{08B92D62-4595-4ACF-B6ED-743B52892E72}</Project>
<Name>TabView.Sample</Name>
</ProjectReference>
<ProjectReference Include="..\Xamarin.Forms.TabView.iOS\Xamarin.Forms.TabView.iOS.csproj">
<Project>{459689E5-163C-49F8-956F-FB31D2C74443}</Project>
<Name>Xamarin.Forms.TabView.iOS</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BundleResource Include="Resources\square.png" />

Просмотреть файл

@ -17,98 +17,110 @@ namespace TabView.Sample.ViewModels
void LoadMonkeys()
{
Monkeys1 = new ObservableCollection<Monkey>
Monkeys1 = new ObservableCollection<Monkey>();
for (int i = 0; i < 100; i++)
{
new Monkey
Monkeys1.Add(new Monkey
{
Index = 0,
Index = i,
Name = "Baboon",
Location = "Africa & Asia",
Details = "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg",
Color = Color.LightSalmon
},
new Monkey
});
Monkeys1.Add(new Monkey
{
Index = 1,
Index = i,
Name = "Capuchin Monkey",
Location = "Central & South America",
Details = "The capuchin monkeys are New World monkeys of the subfamily Cebinae. Prior to 2011, the subfamily contained only a single genus, Cebus.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg",
Color = Color.LightBlue
},
new Monkey
});
Monkeys1.Add(new Monkey
{
Index = 2,
Index = i,
Name = "Blue Monkey",
Location = "Central and East Africa",
Details = "The blue monkey or diademed monkey is a species of Old World monkey native to Central and East Africa, ranging from the upper Congo River basin east to the East African Rift and south to northern Angola and Zambia",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg",
Color = Color.LightSlateGray
}
};
});
}
Monkeys2 = new ObservableCollection<Monkey>
Monkeys2 = new ObservableCollection<Monkey>();
for (int i = 0; i < 50; i++)
{
new Monkey
Monkeys2.Add(new Monkey
{
Index = 3,
Name = "Squirrel Monkey",
Index = i,
Name = "Baboon",
Location = "Africa & Asia",
Details = "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg",
Color = Color.LightSalmon
});
Monkeys2.Add(new Monkey
{
Index = i,
Name = "Capuchin Monkey",
Location = "Central & South America",
Details = "The squirrel monkeys are the New World monkeys of the genus Saimiri. They are the only genus in the subfamily Saimirinae. The name of the genus Saimiri is of Tupi origin, and was also used as an English name by early researchers.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Saimiri_sciureus-1_Luc_Viatour.jpg/220px-Saimiri_sciureus-1_Luc_Viatour.jpg",
Color = Color.Chocolate
},
new Monkey
{
Index = 4,
Name = "Golden Lion Tamarin",
Location = "Brazil",
Details = "The golden lion tamarin also known as the golden marmoset, is a small New World monkey of the family Callitrichidae.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Golden_lion_tamarin_portrait3.jpg/220px-Golden_lion_tamarin_portrait3.jpg",
Color = Color.Violet
},
new Monkey
{
Index = 5,
Name = "Howler Monkey",
Location = "South America",
Details = "Howler monkeys are among the largest of the New World monkeys. Fifteen species are currently recognised. Previously classified in the family Cebidae, they are now placed in the family Atelidae.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Alouatta_guariba.jpg/200px-Alouatta_guariba.jpg",
Color = Color.Aqua
}
};
Details = "The capuchin monkeys are New World monkeys of the subfamily Cebinae. Prior to 2011, the subfamily contained only a single genus, Cebus.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg",
Color = Color.LightBlue
});
Monkeys3 = new ObservableCollection<Monkey>
Monkeys2.Add(new Monkey
{
Index = i,
Name = "Blue Monkey",
Location = "Central and East Africa",
Details = "The blue monkey or diademed monkey is a species of Old World monkey native to Central and East Africa, ranging from the upper Congo River basin east to the East African Rift and south to northern Angola and Zambia",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg",
Color = Color.LightSlateGray
});
}
Monkeys3 = new ObservableCollection<Monkey>();
for (int i = 0; i < 200; i++)
{
new Monkey
Monkeys3.Add(new Monkey
{
Index = 6,
Name = "Japanese Macaque",
Location = "Japan",
Details = "The Japanese macaque, is a terrestrial Old World monkey species native to Japan. They are also sometimes known as the snow monkey because they live in areas where snow covers the ground for months each",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Macaca_fuscata_fuscata1.jpg/220px-Macaca_fuscata_fuscata1.jpg",
Color = Color.OrangeRed
},
new Monkey
Index = i,
Name = "Baboon",
Location = "Africa & Asia",
Details = "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg",
Color = Color.LightSalmon
});
Monkeys3.Add(new Monkey
{
Index = 7,
Name = "Mandrill",
Location = "Southern Cameroon, Gabon, Equatorial Guinea, and Congo",
Details = "The mandrill is a primate of the Old World monkey family, closely related to the baboons and even more closely to the drill. It is found in southern Cameroon, Gabon, Equatorial Guinea, and Congo.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Mandrill_at_san_francisco_zoo.jpg/220px-Mandrill_at_san_francisco_zoo.jpg",
Color = Color.MediumPurple
},
new Monkey
Index = i,
Name = "Capuchin Monkey",
Location = "Central & South America",
Details = "The capuchin monkeys are New World monkeys of the subfamily Cebinae. Prior to 2011, the subfamily contained only a single genus, Cebus.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg",
Color = Color.LightBlue
});
Monkeys3.Add(new Monkey
{
Index = 8,
Name = "Proboscis Monkey",
Location = "Borneo",
Details = "The proboscis monkey or long-nosed monkey, known as the bekantan in Malay, is a reddish-brown arboreal Old World monkey that is endemic to the south-east Asian island of Borneo.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Proboscis_Monkey_in_Borneo.jpg/250px-Proboscis_Monkey_in_Borneo.jpg",
Color = Color.Pink
}
};
Index = i,
Name = "Blue Monkey",
Location = "Central and East Africa",
Details = "The blue monkey or diademed monkey is a species of Old World monkey native to Central and East Africa, ranging from the upper Congo River basin east to the East African Rift and south to northern Angola and Zambia",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg",
Color = Color.LightSlateGray
});
}
}
}
}

Просмотреть файл

@ -0,0 +1,120 @@
using System;
using Android.Content;
using Android.Views;
using Xamarin.Forms;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Platform.Android;
using CarouselView = Xamarin.Forms.TabView.CarouselView;
using CarouselViewRenderer = Xamarin.Forms.TabView.Android.CarouselViewRenderer;
[assembly: ExportRenderer(typeof(CarouselView), typeof(CarouselViewRenderer))]
namespace Xamarin.Forms.TabView.Android
{
[Preserve(AllMembers = true)]
public class CarouselViewRenderer : VisualElementRenderer<CarouselView>
{
readonly float _density;
bool _isSwiping;
float? _downX;
float? _downY;
public CarouselViewRenderer(Context context) : base(context)
{
_density = Resources.DisplayMetrics.Density;
}
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
if (!Element.IsSwipeEnabled || !Element.IsEnabled)
{
base.OnInterceptTouchEvent(ev);
return false;
}
if (ev.ActionMasked == MotionEventActions.Move)
{
float moveX = ev.GetX() / _density;
float moveY = ev.GetY() / _density;
float totalX = moveX - _downX.GetValueOrDefault();
float totalY = moveY - _downY.GetValueOrDefault();
return ShouldInterceptTouchEvent(totalX, totalY);
}
HandleTouchDown(ev);
HandleTouchUpOrCancel(ev);
return false;
}
public override bool OnTouchEvent(MotionEvent ev)
{
if (ev.ActionMasked == MotionEventActions.Move)
HandleTouchMove(ev);
HandleTouchDown(ev);
HandleTouchUpOrCancel(ev);
return true;
}
bool ShouldInterceptTouchEvent(float xDelta, float yDelta)
{
var xDeltaAbs = Math.Abs(xDelta);
var yDeltaAbs = Math.Abs(yDelta);
var isHandled = yDeltaAbs < xDeltaAbs;
Parent?.RequestDisallowInterceptTouchEvent(isHandled);
return isHandled;
}
void HandleTouchDown(MotionEvent ev)
{
if (ev.ActionMasked != MotionEventActions.Down)
return;
_downX = ev.GetX() / _density;
_downY = ev.GetY() / _density;
Element.TouchStarted();
_isSwiping = true;
}
void HandleTouchMove(MotionEvent ev)
{
float moveX = ev.GetX() / _density;
float moveY = ev.GetY() / _density;
float xDelta = moveX - _downX.GetValueOrDefault();
float yDelta = moveY - _downY.GetValueOrDefault();
ShouldInterceptTouchEvent(xDelta, yDelta);
if (Math.Abs(yDelta) <= Math.Abs(xDelta))
Element.TouchChanged(xDelta);
}
void HandleTouchUpOrCancel(MotionEvent ev)
{
var action = ev.ActionMasked;
var isUpAction = action == MotionEventActions.Up;
var isCancelAction = action == MotionEventActions.Cancel;
if (!_isSwiping || (!isUpAction && !isCancelAction))
return;
Element.TouchEnded();
_isSwiping = false;
Parent?.RequestDisallowInterceptTouchEvent(false);
_downX = null;
_downY = null;
}
}
}

Просмотреть файл

@ -0,0 +1,26 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Android.App;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Xamarin.Forms.TabView.Android")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Xamarin.Forms.TabView.Android")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Просмотреть файл

@ -0,0 +1,44 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.xml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable/
icon.png
layout/
main.xml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called "R"
(this is an Android convention) that contains the tokens for each one of the resources
included. For example, for the above Resources layout, this is what the R class would expose:
public class R {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
to reference the layout/main.xml file, or R.strings.first_string to reference the first
string in the dictionary file values/strings.xml.

8629
src/Xamarin.Forms.TabView.Android/Resources/Resource.designer.cs сгенерированный Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="hello">Hello World, Click Me!</string>
<string name="app_name">Xamarin.Forms.TabView.Android</string>
</resources>

Просмотреть файл

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{335288B7-AA6F-487C-B4AA-88B9E3261BD5}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TemplateGuid>{9ef11e43-1701-4396-8835-8392d57abb70}</TemplateGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Xamarin.Forms.TabView.Android</RootNamespace>
<AssemblyName>Xamarin.Forms.TabView.Android</AssemblyName>
<FileAlignment>512</FileAlignment>
<Deterministic>True</Deterministic>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
<AndroidUseAapt2>true</AndroidUseAapt2>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>portable</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Mono.Android" />
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CarouselViewRenderer.cs" />
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\AboutResources.txt" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Forms">
<Version>4.6.0.800</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\strings.xml" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\drawable\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Xamarin.Forms.TabView\Xamarin.Forms.TabView.csproj">
<Project>{5A412691-4D0D-4140-A4B1-1E5660A8D390}</Project>
<Name>Xamarin.Forms.TabView</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,155 @@
using System;
using System.ComponentModel;
using System.Linq;
using CoreGraphics;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Platform.iOS;
using CarouselView = Xamarin.Forms.TabView.CarouselView;
using CarouselViewRenderer = Xamarin.Forms.TabView.iOS.CarouselViewRenderer;
[assembly: ExportRenderer(typeof(CarouselView), typeof(CarouselViewRenderer))]
namespace Xamarin.Forms.TabView.iOS
{
[Preserve(AllMembers = true)]
public class CarouselViewRenderer : VisualElementRenderer<CarouselView>
{
readonly UIPanGestureRecognizer _panGestureRecognizer;
CGPoint _initialPoint;
bool _isSwiping;
public CarouselViewRenderer()
{
_panGestureRecognizer = new UIPanGestureRecognizer(HandlePan)
{
CancelsTouchesInView = false,
DelaysTouchesBegan = false,
DelaysTouchesEnded = false
};
_panGestureRecognizer.ShouldRecognizeSimultaneously = (recognizer, gestureRecognizer) => true;
}
public static void Preserve() => CarouselView.Preserve();
protected override void OnElementChanged(ElementChangedEventArgs<CarouselView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
UpdatePanGesture();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == CarouselView.IsSwipeEnabledProperty.PropertyName)
UpdatePanGesture();
}
void UpdatePanGesture()
{
RemoveGestureRecognizer(_panGestureRecognizer);
if (!Element.IsEnabled || !Element.IsSwipeEnabled)
return;
AddGestureRecognizer(_panGestureRecognizer);
}
void HandlePan(UIPanGestureRecognizer panGestureRecognizer)
{
if (panGestureRecognizer != null)
{
var point = panGestureRecognizer.LocationInView(this);
var navigationController = GetUINavigationController(GetViewController());
switch (panGestureRecognizer.State)
{
case UIGestureRecognizerState.Began:
if (navigationController != null)
navigationController.InteractivePopGestureRecognizer.Enabled = false;
HandleTouchDown(point);
break;
case UIGestureRecognizerState.Changed:
HandleTouchMove(point);
break;
case UIGestureRecognizerState.Ended:
case UIGestureRecognizerState.Cancelled:
if (navigationController != null)
navigationController.InteractivePopGestureRecognizer.Enabled = true;
HandleTouchUpOrCancel();
break;
}
}
}
void HandleTouchDown(CGPoint point)
{
_initialPoint = point;
_isSwiping = true;
Element.TouchStarted();
}
void HandleTouchMove(CGPoint point)
{
nfloat xDelta = point.X - _initialPoint.X;
nfloat yDelta = point.Y - _initialPoint.Y;
if (Math.Abs(yDelta) <= Math.Abs(xDelta))
Element.TouchChanged(xDelta);
}
void HandleTouchUpOrCancel()
{
if (!_isSwiping)
return;
_isSwiping = false;
Element.TouchEnded();
}
UIViewController GetViewController()
{
var window = UIApplication.SharedApplication.GetKeyWindow();
var viewController = window.RootViewController;
while (viewController.PresentedViewController != null)
viewController = viewController.PresentedViewController;
return viewController;
}
UINavigationController GetUINavigationController(UIViewController controller)
{
if (controller != null)
{
if (controller is UINavigationController)
{
return controller as UINavigationController;
}
if (controller.ChildViewControllers.Any())
{
var childs = controller.ChildViewControllers.Count();
for (int i = 0; i < childs; i++)
{
var child = GetUINavigationController(controller.ChildViewControllers[i]);
if (child is UINavigationController)
{
return (child as UINavigationController);
}
}
}
}
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Xamarin.Forms.TabView.iOS")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Xamarin.Forms.TabView.iOS")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("50c7b8c9-e664-45af-b88e-0c9b8b9c1be1")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Просмотреть файл

@ -0,0 +1,26 @@
using UIKit;
namespace Xamarin.Forms.TabView.iOS
{
internal static class UIApplicationExtensions
{
public static UIWindow GetKeyWindow(this UIApplication application)
{
#if __MOBILE__
var windows = application.Windows;
for (int i = 0; i < windows.Length; i++)
{
var window = windows[i];
if (window.IsKeyWindow)
return window;
}
return null;
#else
return application.KeyWindow;
#endif
}
}
}

Просмотреть файл

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{459689E5-163C-49F8-956F-FB31D2C74443}</ProjectGuid>
<ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TemplateGuid>{a52b8a63-bc84-4b47-910d-692533484892}</TemplateGuid>
<OutputType>Library</OutputType>
<RootNamespace>Xamarin.Forms.TabView.iOS</RootNamespace>
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
<AssemblyName>Xamarin.Forms.TabView.iOS</AssemblyName>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
</ItemGroup>
<ItemGroup>
<Compile Include="CarouselViewRenderer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UIApplicationExtensions.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Xamarin.Forms.TabView\Xamarin.Forms.TabView.csproj">
<Project>{5A412691-4D0D-4140-A4B1-1E5660A8D390}</Project>
<Name>Xamarin.Forms.TabView</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Forms">
<Version>4.6.0.800</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
</Project>

Просмотреть файл

@ -14,6 +14,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sample", "Sample", "{E94895
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TabView.Sample.UWP", "TabView.Sample.UWP\TabView.Sample.UWP.csproj", "{61E79B4B-A83D-4D7D-976A-97ABF95641BE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.TabView.Android", "Xamarin.Forms.TabView.Android\Xamarin.Forms.TabView.Android.csproj", "{335288B7-AA6F-487C-B4AA-88B9E3261BD5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.TabView.iOS", "Xamarin.Forms.TabView.iOS\Xamarin.Forms.TabView.iOS.csproj", "{459689E5-163C-49F8-956F-FB31D2C74443}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -175,6 +179,62 @@ Global
{61E79B4B-A83D-4D7D-976A-97ABF95641BE}.Release|x86.ActiveCfg = Release|x86
{61E79B4B-A83D-4D7D-976A-97ABF95641BE}.Release|x86.Build.0 = Release|x86
{61E79B4B-A83D-4D7D-976A-97ABF95641BE}.Release|x86.Deploy.0 = Release|x86
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|ARM.ActiveCfg = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|ARM.Build.0 = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|ARM64.Build.0 = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|iPhone.Build.0 = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|x64.ActiveCfg = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|x64.Build.0 = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|x86.ActiveCfg = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Debug|x86.Build.0 = Debug|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|Any CPU.Build.0 = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|ARM.ActiveCfg = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|ARM.Build.0 = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|ARM64.ActiveCfg = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|ARM64.Build.0 = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|iPhone.ActiveCfg = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|iPhone.Build.0 = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|x64.ActiveCfg = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|x64.Build.0 = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|x86.ActiveCfg = Release|Any CPU
{335288B7-AA6F-487C-B4AA-88B9E3261BD5}.Release|x86.Build.0 = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|Any CPU.Build.0 = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|ARM.ActiveCfg = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|ARM.Build.0 = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|ARM64.Build.0 = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|iPhone.Build.0 = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|x64.ActiveCfg = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|x64.Build.0 = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|x86.ActiveCfg = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Debug|x86.Build.0 = Debug|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|Any CPU.ActiveCfg = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|Any CPU.Build.0 = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|ARM.ActiveCfg = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|ARM.Build.0 = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|ARM64.ActiveCfg = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|ARM64.Build.0 = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|iPhone.ActiveCfg = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|iPhone.Build.0 = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|x64.ActiveCfg = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|x64.Build.0 = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|x86.ActiveCfg = Release|Any CPU
{459689E5-163C-49F8-956F-FB31D2C74443}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

Просмотреть файл

@ -2,12 +2,13 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Xamarin.Forms.TabView
{
public class CarouselView : Grid
public class CarouselView : Grid, ICarouselViewController
{
const double CompletedTransitionPercentage = 0.4;
@ -26,6 +27,12 @@ namespace Xamarin.Forms.TabView
Initialize();
}
[EditorBrowsable(EditorBrowsableState.Never)]
public static void Preserve()
{
}
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create(nameof(ItemsSource), typeof(IList), typeof(CarouselView), null,
propertyChanged: OnItemsSourceChanged);
@ -268,6 +275,10 @@ namespace Xamarin.Forms.TabView
void UpdateIsSwipeEnabled(bool isSwipeEnabled = true)
{
if (Device.RuntimePlatform == Device.Android ||
Device.RuntimePlatform == Device.iOS)
return;
if (isSwipeEnabled)
{
_panGesture.PanUpdated += OnPanUpdated;
@ -285,7 +296,7 @@ namespace Xamarin.Forms.TabView
Transition = tabViewItemTransition;
}
async void OnPanUpdated(object sender, PanUpdatedEventArgs e)
void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
if (_itemsCount < 0)
return;
@ -293,14 +304,14 @@ namespace Xamarin.Forms.TabView
switch (e.StatusType)
{
case GestureStatus.Started:
OnTouchStarted();
TouchStarted();
break;
case GestureStatus.Running:
await OnTouchChanged(e.TotalX);
TouchChanged(e.TotalX);
break;
case GestureStatus.Canceled:
case GestureStatus.Completed:
await OnTouchEnded();
TouchEnded();
break;
}
}
@ -320,12 +331,12 @@ namespace Xamarin.Forms.TabView
UpdateOtherViews();
}
void OnTouchStarted()
public void TouchStarted()
{
UpdateOtherViews();
}
async Task OnTouchChanged(double offset)
public async void TouchChanged(double offset)
{
SetIsDragging(true);
@ -342,7 +353,7 @@ namespace Xamarin.Forms.TabView
RaiseScrolled();
}
async Task OnTouchEnded()
public async void TouchEnded()
{
SetIsDragging(false);
@ -464,7 +475,7 @@ namespace Xamarin.Forms.TabView
UpdateViewIndex(_previousView);
}
}
void AddOrUpdateCache(int key, View value)
{
if (_existingViews == null)
@ -499,10 +510,10 @@ namespace Xamarin.Forms.TabView
_existingViews.TryGetValue(index, out View view);
if (view == null)
{
view = (View)ItemTemplate.CreateContent();
if (view.BindingContext == null)
view.BindingContext = context;
}
return view;
}

Просмотреть файл

@ -0,0 +1,9 @@
namespace Xamarin.Forms.TabView
{
public interface ICarouselViewController
{
void TouchStarted();
void TouchChanged(double offset);
void TouchEnded();
}
}