I am trying to embed a webview into navController, but end up with webview not scrollable at all.
The webpage regardless of its size will not allow to be scrolled. What am I doing wrong here?
using Foundation;
using UIKit;
using System.Drawing;
namespace TestNamespace
{
public class Level2ViewController : UIViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
Title = "Test";
UIWebView webview = new UIWebView (View.Bounds);
View.AddSubview(webview);
webview.LoadRequest (new NSUrlRequest (new NSUrl("https://news.google.com/")));
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
}
}
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to application events from iOS.
[Register ("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
// class-level declarations
UIWindow window;
UINavigationController navController;
public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
window = new UIWindow ();
window.MakeKeyAndVisible ();
navController = new UINavigationController ();
Level2ViewController new1 = new Level2ViewController();
// push the view controller onto the nav controller and show the window
navController.PushViewController(new1, false);
window.RootViewController = navController;
window.MakeKeyAndVisible ();
return true;
}
public override void OnResignActivation (UIApplication application)
{
// Invoked when the application is about to move from active to inactive state.
// This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message)
// or when the user quits the application and it begins the transition to the background state.
// Games should use this method to pause the game.
}
public override void DidEnterBackground (UIApplication application)
{
// Use this method to release shared resources, save user data, invalidate timers and store the application state.
// If your application supports background exection this method is called instead of WillTerminate when the user quits.
}
public override void WillEnterForeground (UIApplication application)
{
// Called as part of the transiton from background to active state.
// Here you can undo many of the changes made on entering the background.
}
public override void OnActivated (UIApplication application)
{
// Restart any tasks that were paused (or not yet started) while the application was inactive.
// If the application was previously in the background, optionally refresh the user interface.
}
public override void WillTerminate (UIApplication application)
{
// Called when the application is about to terminate. Save data, if needed. See also DidEnterBackground.
}
}
}
Write this in ViewDidLoad
webiew.ScrollView.ScrollEnabled = true;
webView.ScalesPageToFit = true;
Related
My Xamarin.iOS project keeps crashing with no explanation, and I reckon it's because of something I'm doing with SendBird, since I'm not seeing any explanation in the application output when my app crashes. How can I see logs of SendBird? This is what I am trying:
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// other code...
SendBird.SendBirdClient.Log = SendBirdLog;
return true;
}
private void SendBirdLog(string message)
{
// this never gets called
Console.WriteLine(message);
}
But my SendBirdLog function never gets called. I am using the latest SendBird.dll from here:
https://github.com/sendbird/Sendbird-SDK-dotNET#before-getting-started
How to get notified when Xamarin Native Android app goes to sleep or is terminated?
When searching, I only found an answer for Xamarin.Forms where the Application object allows to override OnSleep.
The background of this question is that I want to save settings when the app either goes to background or is terminated.
Just like the OnSleep method of Xamarin Forms the OnPause method is called in Android Native when the app goes into the background.
You can override OnPause in both an Activity and a Fragment something like this:
protected override void OnPause()
{
base.OnPause();
// Add your code here
}
Update
You can do the same on application level by adding the Android Application class :
Add a new C# class file in your project called MainApplication.cs.
Then add the Application.IActivityLifecycleCallbacks interface where you can find the activity paused method with the activity context in which it was paused so you can add it and do the needful.
#if DEBUG
[Application(Debuggable = true)]
#else
[Application(Debuggable = false)]
#endif
public class MainApplication : Application , Application.IActivityLifecycleCallbacks
{
public MainApplication(IntPtr handle, JniHandleOwnership transer)
: base(handle, transer)
{
}
public void OnActivityPaused(Android.App.Activity activity)
{
base.OnCreate();
// Add some code
}
public override void OnTerminate()
{
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
}
public override void OnCreate()
{
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
}
}
I have created an application on Xamarin Forms in which I am scheduling local notifications in PCL through a Plugin named Plugin.Notifications. But I wanted to know whether the user enters into the app through notification or not.
I tried to check whether the UIApplication.LaunchOptionsLocalNotificationKey is present in the launch 'options' dictionary or not, but the launch options dictionary is always null.
Then I tried to handle it through the ReceivedLocalNotification delegate method, and I was able to get the tap event, it works fine when the app is in foreground or in the background, but when the app gets killed and opens through tapping on the notification, its getting crashed.
I am unable to find the issue for the crash.
here is what I am doing in the ReceivedLocalNotification method.
I am setting a bool value through a DependencyService.
public override void ReceivedLocalNotification(UIApplication application, UILocalNotification notification)
{
NSUserDefaults.StandardUserDefaults.Init();
DependencyService.Get<INotificationTap>().SetNoitificationTap(true);
}
The handling of the Dependency Service
[assembly: Xamarin.Forms.Dependency(typeof(NotificationTapIOS))]
namespace abc.iOS
{
public class NotificationTapIOS:NSObject,INotificationTap
{
public bool GetNotificationTap()
{
return NSUserDefaults.StandardUserDefaults.BoolForKey("notificationTapKey");
}
public void SetNoitificationTap(bool isNotificationTapped)
{
NSUserDefaults.StandardUserDefaults.SetBool(isNotificationTapped,"notificationTapKey");
NSUserDefaults.StandardUserDefaults.Synchronize();
}
}
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
if (options != null)
{
// check for a local notification
if (options.ContainsKey(UIApplication.LaunchOptionsLocalNotificationKey))
{
var localNotification = options[UIApplication.LaunchOptionsLocalNotificationKey] as UILocalNotification;
if (localNotification != null)
{
LoadApplication(new App());
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;// reset our badge
}
}
}
else
{
LoadApplication(new App());
}
}
I found a workaround for this issue, I don't know whether this is a correct approach, but it worked for me.
In Xamarin.iOS , when the app launched , the base class methods are called first(i.e applicationDidFinishLaunching) and then the Xamarin part(i.e FinishedLaunching) is called.
So I changed the FinishedLaunching parameters names , similar to the base class parameters (i.e 'app' to 'uiApplication' and 'options' to 'launchOptions' ) and I got the key in the launchOptions Dictionary.
public override bool FinishedLaunching(UIApplication uiApplication, NSDictionary launchOptions)
{
global::Xamarin.Forms.Forms.Init();
isNotificationTapped = false;
if (launchOptions != null) {
if (launchOptions.ContainsKey(UIApplication.LaunchOptionsLocalNotificationKey))
isNotificationTapped = true;
}
LoadApplication(new App());
return base.FinishedLaunching(uiApplication, launchOptions);
}
When the user starts the app through notification tap, then FinishedLaunching method of AppDelegate is executed and we can validate the launchOptions dictionary to find the tap event, and if the app is in background or running stage , and user taps on the notification then the RecieveLocalNotification method of the AppDelegate is called.
public override void ReceivedLocalNotification(UIApplication application, UILocalNotification notification)
{
isNotificationTapped = true;
}
After initializing the value , I saved it in the UserDefaults using the DependencyService
I have a timer in the FinishLaunching event inside the AppDelegate which was set to execute every 30 minutes.
If I move the application to the background or even suspended by device, I understand that the Timer will stop, but what happen if it goes back to foreground. Will the Timer continue from where it got stopped.
E.g. After 10 mins from Application start, I switched to application till it got background/suspended. 10 minutes later, I switch it back. Will the timer fires after 10 minutes or started all over again (30mins).
downloadTimer = NSTimer.CreateRepeatingScheduledTimer(30, DownloadEntityFromServer);
NSRunLoop.Current.AddTimer(downloadTimer, NSRunLoopMode.Default);
The timer will not be stopped if the application is suspended. It will keep on firing.
There is no way to pause and resume the timer. Instead please refer the below workaround to pause and resume the timer.
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
NSTimer downloadTimer;
DateTime date;
TimeSpan RemainingMinutes;
bool isBackground;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
downloadTimer = NSTimer.CreateRepeatingScheduledTimer(new TimeSpan(0,30,0), DownloadEntityFromServer);
NSRunLoop.Current.AddTimer(downloadTimer, NSRunLoopMode.Default);
return base.FinishedLaunching(app, options);
}
public override void DidEnterBackground(UIApplication uiApplication)
{
RemainingMinutes = (DateTime.Now - date);
isBackground = true;
base.DidEnterBackground(uiApplication);
}
public override void WillEnterForeground(UIApplication uiApplication)
{
isBackground = false;
CreateTemporaryTimer();
base.WillEnterForeground(uiApplication);
}
void CreateTemporaryTimer()
{
NSTimer tempTimer = NSTimer.CreateScheduledTimer(new TimeSpan(0,30-RemainingMinutes.Minutes,0), TemporaryTimerTicks);
}
void TemporaryTimerTicks(NSTimer obj)
{
downloadTimer.Invalidate();
downloadTimer = NSTimer.CreateRepeatingScheduledTimer(new TimeSpan(0,30,0), DownloadEntityFromServer);
}
void DownloadEntityFromServer(NSTimer obj)
{
date = DateTime.Now;
if (!isBackground)
{
// Write your stuff
}
}
}
I would like to know if there is a working sample for monotouch that shows a working example for receiving remote control events such as those from the headphone buttons.
I have implemented a single view iphone app, implemented CanBecomeFirstResponder, called BecomeFirstResponder and also UIApplication.SharedApplication.BeginReceivingRemoteControlEvents() but I dont get any events.
Here is my code for my SingleViewController.
public partial class SingleViewViewController : UIViewController
{
public SingleViewViewController () : base ("SingleViewViewController", null)
{
}
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 override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Perform any additional setup after loading the view, typically from a nib.
AVAudioSession audioSession = AVAudioSession.SharedInstance();
NSError error;
audioSession.SetCategory(AVAudioSession.CategoryPlayback, out error);
audioSession.SetActive(true,out error);
this.BecomeFirstResponder();
UIApplication.SharedApplication.BeginReceivingRemoteControlEvents();
}
public override void ViewDidUnload ()
{
base.ViewDidUnload ();
// Clear any references to subviews of the main view in order to
// allow the Garbage Collector to collect them sooner.
//
// e.g. myOutlet.Dispose (); myOutlet = null;
ReleaseDesignerOutlets ();
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
public override bool CanBecomeFirstResponder {
get {
return true;
}
}
public override bool CanResignFirstResponder {
get {
return false;
}
}
public override void RemoteControlReceived (UIEvent theEvent)
{
base.RemoteControlReceived (theEvent);
}
}
I spent a little bit of time on this and I think I might have an answer for you. My first faulty assumption was that the volume up and down controls on the remote (headphones) would register but they don't.
I haven't managed to confirm the following except through trial and error, but it appears that you need to have an AVAudioPlayer playing something, or at least playing something when you start the AVAudioSession. Without playing something the play / stop event gets passed to the Music app which handles it.
In your code, in the ViewDidLoad method after the call to base, I added
AVAudioPlayer player = new AVAudioPlayer(new NSUrl("Music/test.m4a", false), null);
player.PrepareToPlay();
player.Play();
If you look at chapter 27 of these samples on GitHub, you'll see an example that plays audio and handles the remote control events.
https://github.com/mattneub/Programming-iOS-Book-Examples
I wasn't able to get remote control events working without the player playing, your example matched lots of Obj-C samples but I couldn't make it work in Xcode either.
Hope this helps.