How can I get Google Glass gestures working with Xamarin? - c#

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;
}
}
}

Related

How do get to implement navigation in Xamarin's Webview for Android?

I am learning some C# for android with xamarin Studio. I followed a tutorial on microsoft docs. Everything was working fine until i added the OnkeyDown() method. The compiler cant find web_view but it right up there.
How can i fix this?
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Webkit;
using Android.Widget;
using Android.OS;
using theWedding.Views;
using theWedding.Models;
namespace theWedding
{
[Activity(Label = "theWedding", MainLauncher = true)]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
var web_view = FindViewById<WebView>(Resource.Id.webview);
web_view.Settings.JavaScriptEnabled = true;
web_view.SetWebViewClient(new TheWeddingClient());
web_view.LoadUrl("https://patahapa.com/apps");
}
public class TheWeddingClient : WebViewClient
{
//for android <7
//public override bool ShouldOverrideUrlLoading(WebView view, string url)
//{
// view.LoadUrl(url);
// return false;
//}
//for android 7+
public override bool ShouldOverrideUrlLoading(WebView view, IWebResourceRequest request)
{
view.LoadUrl(request.Url.ToString());
return false;
}
}
public override bool OnKeyDown(Android.Views.Keycode keyCode, Android.Views.KeyEvent e)
{
if (keyCode == Keycode.Back && web_view.CanGoBack())
{
web_view.GoBack();
return true;
}
return base.OnKeyDown(keyCode, e);
}
}
}
Because you are declaring webview inside OnCreate, it's scope limited to just OnCreate. This is basic C# scoping.
If you instead declare webview at the class level, it will be available everywhere in the class.
// declare at the class level
WebView webview;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
web_view = FindViewById<WebView>(Resource.Id.webview);
web_view.Settings.JavaScriptEnabled = true;
web_view.SetWebViewClient(new TheWeddingClient());
web_view.LoadUrl("https://patahapa.com/apps");
}

Xamarin-iOS today widget, unable to load issue

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.

How do I update a ListView?

Hi guys I have a problem. I have a DialogFragment with content that is saved in a sqlite db on the phone, and a Fragment that retrieves the information and shows it. The ListView initially (upon creation) shows everything like its supposed to, but when the stuff is updated inside the Dialog Fragment, I dont know how to update the adapter for ListView. Here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
namespace Zrelya.Fragments
{
public class OnSelectedEventArgs : EventArgs
{
public ORM.Plan Plan { get; set; }
public OnSelectedEventArgs( ORM.Plan plan )
{
Plan = plan;
}
}
public class ViewPlans : FragmentSuper
{
private Context mContext;
private ORM.DBRep dbr;
public EventHandler<OnSelectedEventArgs> OnSelected;
public ViewPlans(Context context)
{
mContext = context;
}
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
dbr = new ORM.DBRep();
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
var view = inflater.Inflate(Resource.Layout.ViewPlans, container, false);
var listView = view.FindViewById<ListView>(Resource.Id.listView);
List<ORM.Plan> plansList = dbr.GetPlans();
Adapters.Plan adapter = new Adapters.Plan(mContext, plansList);
listView.Adapter = adapter;
listView.ItemClick += (o, e) =>
{
int id = plansList[e.Position].Id;
OnSelected.Invoke(this, new OnSelectedEventArgs(plansList[e.Position]));
};
return view;
}
}
}
OnSelected.Invoke is what happens when an item is clicked, showing the dialog fragment. The following code is a snippet from MainActivity OnCreate method:
fragmentViewPlans.OnSelected += (o, e) =>
{
int id = e.Plan.Id;
DialogViewPlan(e.Plan);
};
...and the DialogViewPlan method is below:
private void DialogViewPlan(ORM.Plan plan)
{
if (plan != null)
{
Android.App.FragmentTransaction transaction = FragmentManager.BeginTransaction();
Helpers.DialogViewPlan dialog = new Helpers.DialogViewPlan(this, plan);
dialog.Show(transaction, "dialog");
dialog.OnDelete += delegate
{
Toast.MakeText(this, "Plan deleted...", ToastLength.Short).Show();
};
dialog.OnSave += delegate
{
Toast.MakeText(this, "Plan saved!", ToastLength.Short).Show();
};
}
}
I dont know how to talk between activity, fragment and dialog fragment, does anyone know how to do this?
I found an answer:
using Android.App;
using Android.Content;
using Android.OS;
using Android.Views;
using Android.Widget;
using System;
using System.Collections.Generic;
namespace Zrelya.Fragments
{
public class OnSelectedEventArgs : EventArgs
{
public ORM.Plan Plan { get; set; }
public OnSelectedEventArgs( ORM.Plan plan )
{
Plan = plan;
}
}
public class ViewPlans : FragmentSuper
{
private Context mContext;
private ORM.DBRep dbr;
private static Adapters.Plan Adapter;
private static ListView listView;
public EventHandler<OnSelectedEventArgs> OnSelected;
public ViewPlans(Context context)
{
mContext = context;
}
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
dbr = new ORM.DBRep();
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
var view = inflater.Inflate(Resource.Layout.ViewPlans, container, false);
listView = view.FindViewById<ListView>(Resource.Id.listView);
List<ORM.Plan> plansList = dbr.GetPlans();
Adapter = new Adapters.Plan(mContext, plansList);
listView.Adapter = Adapter;
listView.ItemClick += (o, e) =>
{
int id = plansList[e.Position].Id;
var plan = plansList[e.Position];
DialogViewPlan(plan);
};
return view;
}
private void DialogViewPlan(ORM.Plan plan)
{
if (plan != null)
{
FragmentTransaction transaction = Activity.FragmentManager.BeginTransaction();
Helpers.DialogViewPlan dialog = new Helpers.DialogViewPlan(Activity, plan);
dialog.Show(transaction, "dialog");
dialog.OnDelete += delegate
{
Adapter = new Adapters.Plan(mContext, dbr.GetPlans());
listView.Adapter = Adapter;
};
dialog.OnSave += delegate
{
Adapter = new Adapters.Plan(mContext, dbr.GetPlans());
listView.Adapter = Adapter;
};
}
}
}
}

Dismiss soft keyboard

I have a page where the idea is to use it with external keyboards. When the page loads, I set the focus on an Entry control and I want to hide the soft keyboard.
This is the class where I want to do that:
internal class RedactContent : ContentPage
{
StackLayout stack = new StackLayout();
Entry entry;
internal RedactContent()
{
entry = new Entry();
Content = new StackLayout
{
Children = {
entry,
//more code
}
};
}
protected override void OnAppearing()
{
base.OnAppearing();
entry.Focus();
// Hide Keyboard
}
}
How can I do that?
It is possible to create CustomEntry with CloseKeyboard method. For this you need to write custom renderers for each platform. See http://developer.xamarin.com/guides/cross-platform/xamarin-forms/custom-renderer/
On Android your CustomEntry class could look like this:
[assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryRenderer))]
public class CustomEntryRenderer : EntryRenderer
{
public CustomEntryRenderer()
{
HideKeyboard();
}
void HideKeyboard()
{
this.Control.InputType = 0;
InputMethodManager inputMethodManager = this.Control.Context.GetSystemService(Context.InputMethodService) as InputMethodManager;
inputMethodManager.HideSoftInputFromWindow(this.Control.WindowToken, HideSoftInputFlags.ImplicitOnly);
}
// ...
}
* First create a derivated class from Entry
public class KBLessEntry : Entry
{
public KBLessEntry() : base()
{
}
}
* Then create a custom platform EntryRender
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using MobileClients.Droid.Core;
using Android.Views.InputMethods;
using System;
using System.ComponentModel;
[assembly: ExportRenderer(typeof(KBLessEntry), typeof(KBLessEntryRender))]
namespace MobileClients.Droid.Core
{
public class KBLessEntryRender : EntryRenderer
{
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
Control.InputType = 0;
try
{
// Hide keyboard
InputMethodManager inputMethodManager = this.Control.Context.GetSystemService(Android.Content.Context.InputMethodService) as InputMethodManager;
if (inputMethodManager != null)
{
inputMethodManager.HideSoftInputFromWindow(this.Control.WindowToken, HideSoftInputFlags.None);
}
}
catch(Exception Ex)
{
}
}
}
}
And in XAML
<local:KBLessEntry x:Name="TxtCode" FontSize="18" Placeholder="Código producto" TextColor="Black" HorizontalOptions="FillAndExpand"></local:KBLessEntry>
local: must be defined has a namespace in your xaml xmlns:local="clr-namespace:MobileClients.Droid.Core;assembly=MobileClients.Droid" where the derivated Entry class (in this case KBLessEntry) resides
And thats it
View view = ActivityCreateAccount.this.getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager)
getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}

first time programming app for android using monoDevelop (C#) cant understand bug

Error CS0508: 'my_android_project.ImageAdapter.GetItem(int)': return type must be 'Java.Lang.Object' to match overridden member 'Android.Widget.BaseAdapter.GetItem(int)
Here is my first class:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace my_android_project
{
[Activity (Label = "my_android_project", MainLauncher = true)]
public class Activity1 : Activity
{
int count = 1;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
var gridview = FindViewById<GridView> (Resource.Id.gridview);
gridview.ItemClick += delegate(object sender, ItemEventArgs args) {
Toast.MakeText (this, EventArgs.Postion.ToString () , ToastLength.Short).Show();
};
// 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++); };
}
}
}
Second Class:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace my_android_project
{
// base class is ImageAdapter , derived class is BaseAdapter
/// <summary>
/// class start
/// </summary>
public class ImageAdapter : BaseAdapter
{
private readonly Context context;
public ImageAdapter(Context c)
{
context = c;
}
public override int Count
{
get { return thumbIds.Length; }
}
public override Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return 0;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
ImageView imageView;
if (convertView == null)
{
// if it's not recycled, initialize some attributes
imageView = new ImageView(context);
imageView.LayoutParameters = new AbsListView.LayoutParams(85, 85);
imageView.SetScaleType(ImageView.ScaleType.CenterCrop);
imageView.SetPadding(8, 8, 8, 8);
}
else
{
imageView = (ImageView) convertView;
}
imageView.SetImageResource(thumbIds[position]);
return imageView;
} // end of GetView
private readonly int[] thumbIds = {
Resource.Drawable.sample_2,
Resource.Drawable.sample_3,
Resource.Drawable.sample_4,
Resource.Drawable.sample_5,
Resource.Drawable.sample_6,
Resource.Drawable.sample_7,
Resource.Drawable.sample_0,
Resource.Drawable.sample_1,
Resource.Drawable.sample_2,
Resource.Drawable.sample_3,
Resource.Drawable.sample_4,
Resource.Drawable.sample_5,
Resource.Drawable.sample_6,
Resource.Drawable.sample_7,
Resource.Drawable.sample_0,
Resource.Drawable.sample_1,
Resource.Drawable.sample_2,
Resource.Drawable.sample_3,
Resource.Drawable.sample_4,
Resource.Drawable.sample_5,
Resource.Drawable.sample_6,
Resource.Drawable.sample_7
}; // end of thumbIds array
} // end of class
} // end of namespace
looks like on line 32 of my 2nd class Mono Develop does not like that 'null' return ..
any ideas? Im in process of learning C# and a bit more comfortable with it that android app dev :)
The issue is actually your second GetItem() method. The base class defines an abstract object getItem(int position) (per http://developer.android.com/reference/android/widget/BaseAdapter.html) so your second method isn't overriding anything.

Categories

Resources