Xamarin-iOS today widget, unable to load issue - c#

I'm making today widget extension, where I get symbols of coins and then I am making web request to get objects.
In every reload, widget is drawing view again and calling WidgetPerformUpdate method, from 1/10 widget show's me unable to load.
I debuged app and issue is coming at me when I'm adding some objects into widget.
I've stacked in this problem about 1 week, I've read all today widget documentation,tutorials there is no help from nowhere.
I don't know what to do, unable to load is my nightmare.
There is my TodawyWidgetViewController code.
using System;
using System.Collections.Generic;
using NotificationCenter;
using Foundation;
using UIKit;
using CryptoCurrencyPCL.POCO;
using CryptoCurrencyPCL.Middleware;
using System.Linq;
using System.Threading.Tasks;
using CryptoCurrencyPCL.Extensions;
using CryptoCurrencyPCL.Enums;
using CoreGraphics;
using Newtonsoft;
using Newtonsoft.Json;
using CryptoPCL.POCO;
namespace CryptoTodayWidget
{
public partial class TodayViewController : UIViewController, INCWidgetProviding,IUITableViewDataSource,IUITableViewDelegate
{
NSUserDefaults userDefaults;
const string ReuseId = "currencyCellReuseId";
List<CoinDetail> _coins;
List<CoinDetail> _cachedCoins;
List<FavoriteCoin> _favorites;
List<string> listOfStrings = new List<string>();
Currency itemCurrency;
private CGSize _maxSize;
private string nsStringForValues;
private string nsString;
private List<string> deserializedObjectsSymbols;
bool _firstInit = true;
protected TodayViewController(IntPtr handle) : base(handle)
{
// Note: this .ctor should not contain any initialization logic.
}
public override void DidReceiveMemoryWarning()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
public UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell(ReuseId, indexPath) as WidgetCell;
var item = _coins[indexPath.Row];
var favorite = _favorites[indexPath.Row];
cell.InitData(item,favorite,itemCurrency);
return cell;
}
public nint RowsInSection(UITableView tableView, nint section)
{
return _coins?.Count ?? 0;
}
[Export("tableView:heightForRowAtIndexPath:")]
public nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
return 50;
}
[Export("numberOfSectionsInTableView:")]
public nint NumberOfSections(UITableView tableView)
{
return 1;
}
public async override void ViewDidLoad()
{
base.ViewDidLoad();
var webClient = CryptoCurrencyPCL.Services.CryptoWebClient.Instance;
tableView.SeparatorStyle = UITableViewCellSeparatorStyle.None;
_cachedCoins = _coins;
if(_coins != null) {
initTableView();
}
ExtensionContext.SetWidgetLargestAvailableDisplayMode(NCWidgetDisplayMode.Expanded);
}
private void initTableView()
{
tableView.DataSource = this;
tableView.Delegate = this;
tableView.AllowsSelection = false;
tableView.ReloadData();
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
}
[Export("widgetPerformUpdateWithCompletionHandler:")]
public async void WidgetPerformUpdate(Action<NCUpdateResult> completionHandler)
{
var webClient = CryptoCurrencyPCL.Services.CryptoWebClient.Instance;
try
{
initLoading();
bool check = false;
userDefaults = new NSUserDefaults("group.com.mpdc.todayextension", NSUserDefaultsType.SuiteName);
nsStringForValues = userDefaults?.StringForKey(new NSString("MyAppsValues"));
nsString = userDefaults?.StringForKey("currencyKey");
itemCurrency = (Currency)Enum.Parse(typeof(Currency), nsString);
_favorites = JsonConvert.DeserializeObject<List<FavoriteCoin>>(nsStringForValues);
deserializedObjectsSymbols = _favorites.Select(o => o.FavoriteCoinSymbol).ToList();
_coins = await webClient.GetMultiCoinDetailsAsync(deserializedObjectsSymbols, itemCurrency);
if (ExtensionContext.GetWidgetLargestAvailableDisplayMode() == NCWidgetDisplayMode.Compact)
{
this.PreferredContentSize =_maxSize;
}
else
{
this.PreferredContentSize = new CoreGraphics.CGSize(0, _coins.Count * 50);
}
initTableView();
initLoading(false);
tableView.SeparatorStyle = UITableViewCellSeparatorStyle.SingleLine;
completionHandler(NCUpdateResult.NewData);
}
catch (Exception ex)
{
initLoading(false);
completionHandler(NCUpdateResult.Failed);
Console.WriteLine(ex);
}
}
void initLoading(bool visible = true)
{
if (visible)
{
ActivityIndicator.Hidden = false;
ActivityIndicator.StartAnimating();
return;
}
ActivityIndicator.Hidden = true;
ActivityIndicator.StopAnimating();
}
[Export("widgetActiveDisplayModeDidChange:withMaximumSize:")]
public void WidgetActiveDisplayModeDidChange(NCWidgetDisplayMode activeDisplayMode, CoreGraphics.CGSize maxSize)
{
_maxSize = maxSize;
if (activeDisplayMode == NCWidgetDisplayMode.Compact)
{
this.PreferredContentSize = _maxSize;
}
else
{
if(_coins!=null)
this.PreferredContentSize = new CoreGraphics.CGSize(0, _coins.Count * 50);
}
}
}
}
Thank you

I solved it.
It was working on simulator but not on the device.
The problem was happening when I was running my application on the device in debug mode.
I think with debug mode, there were happening memory issues.
I've run it in release mode and everything is working.

Related

How have a custom UICollectionViewCell fill horizontal width?

I'm trying to make an app for people of my student dancing association to find a dance partner. It's been a fun project during corona. Everything is done in ASP Core 5 and Xamarin Forms, and it's almost ready for testing. However, I'm having some trouble with the chat UI. When I use a CollectionView in Forms, it loads very slowly, due to rendering performance (at least on Android, iOS is generally much faster). To solve that I tried creating it as a view and use native renderers for iOS and Android. With Android, I simply used a NuGet package (XamarinLibrary.Xamarin.AndroidX.ChatKit), but for iOS I could find no such package. There's a native SwiftUI package (MessageKit), though I don't know how to wrap that (and the documentation is a lot). So I started to instead write it in Xamarin iOS. My test loads really quickly, although I'm now struggling with the layout of the Collection and the ViewCell. Could someone show me how to create message cells that fill the horizontal space?
Thanks in advance! :)
This is what it looks like right now:
Screenshot
[UPDATE] I partially solved the issue by adding this (though it does not work in the constructor):
Screenshot 2
public override bool ShouldInvalidateLayoutForBoundsChange(CGRect newBounds) {
MinimumLineSpacing = 10;
MinimumInteritemSpacing = 10;
SectionInset = new UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10);
ItemSize = new CGSize(width: (newBounds.Width - 20), height: 100);
return true;
}
My code currently (the data source isn't correct yet):
public class MessageListLayout : UICollectionViewFlowLayout {
public MessageListLayout() {
ItemSize = new CGSize(UIScreen.MainScreen.Bounds.Size.Width, 50);
EstimatedItemSize = AutomaticSize;
}
public override bool ShouldInvalidateLayoutForBoundsChange(CGRect newBounds) {
return true;
}
public override UICollectionViewLayoutAttributes LayoutAttributesForItem(NSIndexPath path) {
return base.LayoutAttributesForItem(path);
}
public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect(CGRect rect) {
return base.LayoutAttributesForElementsInRect(rect);
}
}
public class MessageListDataSource : UICollectionViewDataSource {
private string CellId { get; set; }
#region Computed Properties
public UICollectionView CollectionView { get; set; }
public List<int> Numbers { get; set; } = new List<int>();
#endregion
#region Constructors
public MessageListDataSource(UICollectionView collectionView, string cellId) {
// Initialize
CollectionView = collectionView;
CellId = cellId;
// Init numbers collection
for (int n = 0; n < 100; ++n) {
Numbers.Add(n);
}
}
#endregion
#region Override Methods
public override nint NumberOfSections(UICollectionView collectionView) {
// We only have one section
return 1;
}
public override nint GetItemsCount(UICollectionView collectionView, nint section) {
// Return the number of items
return Numbers.Count;
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath) {
// Get a reusable cell and set {~~it's~>its~~} title from the item
var cell = collectionView.DequeueReusableCell(CellId, indexPath) as MessageListViewCell;
cell.Text = Numbers[(int)indexPath.Item].ToString();
return cell;
}
public override bool CanMoveItem(UICollectionView collectionView, NSIndexPath indexPath) {
// We can always move items
return true;
}
public override void MoveItem(UICollectionView collectionView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath) {
// Reorder our list of items
var item = Numbers[(int)sourceIndexPath.Item];
Numbers.RemoveAt((int)sourceIndexPath.Item);
Numbers.Insert((int)destinationIndexPath.Item, item);
}
#endregion
}
So this should be the base message bubble.
public class MessageListViewCell : UICollectionViewCell {
UIImageView imageView;
public string Text { get; set; }
[Export("initWithFrame:")]
public MessageListViewCell(CGRect frame) : base(frame) {
BackgroundView = new UIView { BackgroundColor = UIColor.Orange };
SelectedBackgroundView = new UIView { BackgroundColor = UIColor.Green };
ContentView.Layer.BorderColor = UIColor.LightGray.CGColor;
ContentView.Layer.BorderWidth = 2.0f;
ContentView.BackgroundColor = UIColor.White;
//ContentView.Transform = CGAffineTransform.MakeScale(1, 1);
ContentView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth;
imageView = new UIImageView(UIImage.FromBundle("placeholder.png"));
imageView.Center = ContentView.Center;
imageView.Transform = CGAffineTransform.MakeScale(0.7f, 0.7f);
ContentView.AddSubview(imageView);
}
public UIImage Image {
set {
imageView.Image = value;
}
}
[Export("custom")]
public void Custom() {
// Put all your custom menu behavior code here
Console.WriteLine("custom in the cell");
}
public override bool CanPerform(Selector action, NSObject withSender) {
if (action == new Selector("custom"))
return true;
else
return false;
}
}
[assembly: ExportRenderer(typeof(MessagesListControl), typeof(MessagesListControlRenderer))]
namespace Vinder.iOS.UI.Renderers {
public class MessagesListControlRenderer : ViewRenderer<MessagesListControl, UICollectionView> {
static readonly NSString messageListViewCell = new("MessageListViewCell");
private UICollectionView collectionView { get; set; }
protected override void OnElementChanged(ElementChangedEventArgs<MessagesListControl> e) {
base.OnElementChanged(e);
if (e.OldElement != null) {
// Unsubscribe to events
}
if (e.NewElement != null) {
if (Control == null) {
collectionView = new UICollectionView(new CGRect(0, 0, UIScreen.MainScreen.Bounds.Size.Width, 300), new MessageListLayout());
collectionView.RegisterClassForCell(typeof(MessageListViewCell), messageListViewCell);
collectionView.BackgroundColor = UIColor.Blue; // blue is easy for seeing the correct bounds
collectionView.DataSource = new MessageListDataSource(collectionView, messageListViewCell);
SetNativeControl(collectionView);
}
// Subscribe to events
}
}
}
}

Xamarin iOS TableView not showing up

I am making an app for iOS using Xamarin I had some trouble with UITableViews and found this tutorial: https://learn.microsoft.com/en-us/xamarin/ios/user-interface/controls/tables/populating-a-table-with-data
I created a new project and followed what they did, but it doesn't work for me. I must be doing something wrong, but I can't figure out what.
Could someone take a look and see why the TableView doesn't show up?
BasicViewController:
public class BasicTableViewController : UIViewController
{
private UIView view;
public override void ViewDidLoad()
{
base.ViewDidLoad();
var table = new UITableView(View.Bounds);
table.Source = new BasicTableSource("aaaaaaaaa", "bbbbb", "cccccccc", "ddddddddddddd", "eeeee");
Add(table);
}
public override void LoadView()
{
view = new UIView()
{
BackgroundColor = UIColor.White,
};
View = view;
}
}
BasicTableViewSource:
public class BasicTableSource : UITableViewSource
{
private readonly string[] items;
public BasicTableSource(params string[] items)
{
this.items = items;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell("cell");
if (cell == null)
cell = new UITableViewCell(UITableViewCellStyle.Default, "cell");
cell.TextLabel.Text = items[indexPath.Row];
return cell;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return items.Length;
}
}
AppDelegate:
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
Window = new UIWindow(UIScreen.MainScreen.Bounds);
Window.RootViewController = new BasicTableViewController();
Window.MakeKeyAndVisible();
return true;
}
}
What the simulator looks like when running this project:
What the simulator looks like
Cause:
When you override the method LoadView.It seems that you forgot to set the Frame of view.So the size of view will with Height as 0 and Width as 0.
Solution:
Set the frame of view as the size of screen.
public override void LoadView()
{
view = new UIView()
{
Frame = UIScreen.MainScreen.Bounds,
BackgroundColor = UIColor.White,
};
View = view;
}

Bind second UITableView on RowClick of first UITableView in the same UIViewController - ios Xamarin

I have two UITableView in the same UIViewController.
tblView1 & tblView2.
Both TableViews are bringing data dynamically.
Now my problem is: I want to load data in tblView2 on the basis of SelectedRow from tblView1.
For Example, when I select a company name from tblView1, then tblView2 needs to populate the Cars made by that company.
I have rowIndex of my first table (tblView1), but i can't bind my tblView2 from the RowSelected Method of tblView1.
I need help in binding my tblView2. How can i do this?
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using CoreGraphics;
using Foundation;
using UIKit;
namespace Tables
{
public partial class ViewController : UIViewController
{
protected ViewController(IntPtr handle) : base(handle)
{
// Note: this .ctor should not contain any initialization logic.
}
public ViewController()
{
//tblView2.Source = new CompanyModelsSource();
// Note: this .ctor should not contain any initialization logic.
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
if (tblView1 != null)
{
tblView1.Source = new CarModelsSource();
}
// Perform any additional setup after loading the view, typically from a nib.
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
}
class CompanyModelsSource : UITableViewSource
{
private List<Companies> _Companies;
NSString _cellID = new NSString("TableCell");
public CompanyModelsSource()
{
_Companies = CompanyTableSource.AllCompany();
}
public override nint RowsInSection(UITableView tableview, nint section)
{
// tell the TableView how many rows to create
return _Companies.Count;
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
//I can't access my tblView2 in this method. So where i can bind my other UITableView?
UILabel lblTotalFacilities = new UILabel();
lblTotalFacilities.Layer.BackgroundColor = UIColor.Blue.CGColor;
lblTotalFacilities.Frame = new CGRect(305, 200, 1024, 400);
ViewController vc = new ViewController();
vc.View.AddSubview(lblTotalFacilities);
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
Company currentCompany = _Companies[indexPath.Row];
var cell = tableView.DequeueReusableCell(_cellID) as CompanyTableCell;
if (cell == null) { cell = new CompanyTableCell(_cellID); }
cell.UpdateCellControlsWithAuditData(currentCompany.Name);
return cell;
}
}
public class CompanyTableSource
{
public CompanyTableSource()
{
}
public static List<Companies> AllCompany()
{
CompanyCollection CC = null;
string path1 = path + "Companies.xml";
XmlSerializer serializer = new XmlSerializer(typeof(CompanyCollection));
StreamReader reader = new StreamReader(path1);
CC = (CompanyCollection)serializer.Deserialize(reader);
reader.Close();
List<Companies> comp = CC.CompanyCollection.Cast<Companies>().ToList();
return comp;
}
}
public class CompanyTableCell : UITableViewCell
{
UILabel nameLabel;
public CompanyTableCell(NSString cellId) : base(UITableViewCellStyle.Default, cellId)
{
SelectionStyle = UITableViewCellSelectionStyle.Gray;
ContentView.BackgroundColor = UIColor.FromRGB(54, 194, 36);
var newFont = UIFont.SystemFontOfSize(12);
nameLabel = new UILabel();
nameLabel.Font = newFont;
ContentView.AddSubviews(new UIView[] { nameLabel });
}
public void UpdateCellControlsWithAuditData(string Name)
{
nameLabel.Text = Name;
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
nameLabel.Frame = new CGRect(10, 0, 350, 33);
}
}
}
Hope this helps. Created everything in a single file for simplicity.
public partial class ViewController : UIViewController
{
public ViewController() : base("ViewController", null)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
var companySource = new CompanyTableSource();
tblView1.Source = companySource;
companySource.ItemSelected += OnCompanyItemSelected;
}
//this will handle the ItemSelected event
//here you will retrieve the data for the second UITableView
void OnCompanyItemSelected(object sender, Company e)
{
//you can do it this way
tblView2.Source = new CarTableSource(e.Id);
List<Car> cars = GetCarsByCompanyId(e.Id);
//or this whay
tblView2.Source = new CarTableSource(cars);
}
List<Car> GetCarsByCompanyId(int id)
{
//Your logic to get the data goes here
throw new NotImplementedException();
}
}
public class CompanyTableSource : UITableViewSource
{
// You can use the whole object or just an integer (companyId)
public event EventHandler<Company> ItemSelected;
public IList<Company> Items { get; private set; } = new List<Company>();
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
var item = Items[indexPath.Row];
ItemSelected?.Invoke(this, item);
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
//Do your implementation
throw new NotImplementedException();
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return Items.Count;
}
}
public class CarTableSource : UITableViewSource
{
public IList<Car> Items { get; private set; } = new List<Car>();
public CarTableSource(int companyId)
{
//Get your data based on the companyId
}
//Or pass in the data already retreived. (I preffer this method)
public CarTableSource(IList<Car> cars)
{
Items = cars;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
//Do your implementation
throw new NotImplementedException();
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return Items.Count;
}
}

iOS TableView button is being called multiple times

I have a TableView with a custom UITableViewCell. In each cell I have multiple buttons, when any of the buttons is click after scrolling down and up it calls itself the many times I scroll down and up.
I have read and research for a solution and I haven't found a solution.
I know the problem is the cell are being reuse so that's why the buttons are being call multiple times but I can't find a way to prevent it.
I added console write line statements through the code and the else part in MoveToWindow is never call. Could that be the reason why?
Research material for solution:
my code is calling twice the btndelete method in uitableview
UIButton click event getting called multiple times inside custom UITableViewCell
My Code:
namespace Class.iOS
{
public partial class CustomCell : UITableViewCell
{
public static readonly NSString Key = new NSString ("CustomCell");
public static readonly UINib Nib;
public int Row { get; set; }
public event EventHandler LikeButtonPressed;
private void OnLikeButtonPressed()
{
if (LikeButtonPressed != null)
{
LikeButtonPressed(this, EventArgs.Empty);
}
}
public override void MovedToWindow()
{
if (Window != null)
{
btnAdd.TouchUpInside += HandleLikeButtonPressed;
}
else
{
btnAdd.TouchUpInside -= HandleLikeButtonPressed;
}
}
private void HandleLikeButtonPressed(object sender, EventArgs e)
{
OnLikeButtonPressed();
}
static CustomCell ()
{
Nib = UINib.FromName ("CustomCell", NSBundle.MainBundle);
}
public CustomCell ()
{
}
public CustomCell (IntPtr handle) : base (handle)
{
}
public void UpdateCell (string Name, int number)
{
// some code
}
public class TableSource : UITableViewSource
{
public override nint RowsInSection (UITableView tableview, nint section)
{
return 8;
}
private void HandleLikeButtonPressed(object sender, EventArgs e)
{
var cell = (CustomCell)sender;
var row = cell.Row;
switch (row)
{
case 0:
cell.label.Text = ""
break;
case 1:
cell.label.Text = ""
break;
}
}
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell (CustomCell.Key) as CustomCell;
cell.Row = indexPath.Row;
if (cell == null)
{
cell = new CustomCell ();
var views = NSBundle.MainBundle.LoadNib("CustomCell", cell, null);
cell.LikeButtonPressed += HandleLikeButtonPressed;
cell = Runtime.GetNSObject( views.ValueAt(0) ) as CustomCell;
}
cell.UpdateCell
(
// some code
);
return cell;
}
}
}
}
The cells are reused in iOS, so you need to make sure you properly unhook handlers and reset state when a cell is reused. You can do something like this:
public partial class CustomCell : UITableViewCell {
EventHandler _likeButtonHandler;
public static readonly NSString Key = new NSString (typeof(CustomCell).Name);
public static readonly UINib Nib = UINib.FromName (typeof(CustomCell).Name, NSBundle.MainBundle);
public CustomCell ()
{
}
public CustomCell (IntPtr handle) : base (handle)
{
}
public override void PrepareForReuse ()
{
LikeButton.TouchUpInside -= _likeButtonHandler;
_likeButtonHandler = null;
base.PrepareForReuse ();
}
public void SetupCell (int row, string Name, EventHandler likeBtnHandler)
{
_likeButtonHandler = likeBtnHandler;
LikeButton.TouchUpInside += _likeButtonHandler;
LikeButton.Tag = row;
NameLabel.Text = Name;
RowLabel.Text = row.ToString ();
}
Notice that I unhook the event handler in the PrepareForReuse override. This is the correct place to do clean up and reset a cell for reuse. You should NOT be using MovedToWindow().
Then your GetCell method will look like this:
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell (CustomCell.Key) as CustomCell ?? new CustomCell ();
cell.SetupCell (indexPath.Row, _fruits [indexPath.Row], _likeButtonHandler);
return cell;
}
The _likeButtonHandler is a simple EventHandler.

How can I get Google Glass gestures working with Xamarin?

I'm using Xamarin to build a Google Glass application, and haven't been able to get the GestureDetector to fire any OnGesture events. Here is what I've tried so far:
In my Activity:
using Gesture = Android.Glass.Touchpad.Gesture;
using GestureDetector = Android.Glass.Touchpad.GestureDetector;
private GestureDetector _gestureDetector;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
this._gestureDetector = new GestureDetector(this);
this._gestureDetector.SetBaseListener(new GestureListener());
}
public override bool OnGenericMotionEvent(MotionEvent e)
{
if (this._gestureDetector != null)
{
return this._gestureDetector.OnMotionEvent(e);
}
return false;
}
The IBaseListener implementation:
class GestureListener : GestureDetector.IBaseListener
{
public bool OnGesture(Gesture gesture)
{
if (gesture == Gesture.SwipeRight)
{
// do something on right (forward) swipe
return true;
}
else if (gesture == Gesture.SwipeLeft)
{
// do something on left (backwards) swipe
return true;
}
return false;
}
public void Dispose()
{
}
public IntPtr Handle { get; set; }
}
I tried setting a breakpoint just inside the OnGesture method, but it is never triggered. Is there something missing from my IBaseListener implementation?
It turns out that I needed to make my listener implementation extend Java.Lang.Object, as mentioned in the Xamarin article about Android Callable Wrappers. Below is a fully working sample Activity.
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Gesture = Android.Glass.Touchpad.Gesture;
using GestureDetector = Android.Glass.Touchpad.GestureDetector;
namespace GlassGestureTest
{
using Android.Util;
using Java.Util.Logging;
[Activity(Label = "GlassGestureTest", MainLauncher = true, Icon = "#drawable/icon")]
public class Activity1 : Activity
{
private GestureDetector _gestureDetector;
int count = 1;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };
this._gestureDetector = new GestureDetector(this);
this._gestureDetector.SetBaseListener(new GestureListener());
}
public override bool OnGenericMotionEvent(MotionEvent e)
{
if (this._gestureDetector != null)
{
return this._gestureDetector.OnMotionEvent(e);
}
return false;
}
}
// Note - the key part here is to extend Java.Lang.Object in order to properly setup
// the IntPtr field and Dispose method required by IBaseListener
public class GestureListener : Java.Lang.Object, GestureDetector.IBaseListener
{
public bool OnGesture(Gesture gesture)
{
if (gesture == Gesture.SwipeRight)
{
// do something on right (forward) swipe
return true;
}
else if (gesture == Gesture.SwipeLeft)
{
// do something on left (backwards) swipe
return true;
}
else if (gesture == Gesture.SwipeDown)
{
// do something on the down swipe
return true;
}
else if (gesture == Gesture.SwipeUp)
{
// do something on the up swipe
return true;
}
return false;
}
}
}

Categories

Resources