Navigation service from forms to iOS - xamarin.forms

I need to acmes view controller from forms page. Is there anything like this for IOS
is there any version of this in droid in iOS
public class NavigationImplementation : INavigationContract
{
public void Push()
{
var second = new Intent(MainActivity.activity, typeof(ScannerActivity));
MainActivity.activity.StartActivity(second);
}
}

In Xamarin iOS, there are two ways to navigate to next page.
One is NavigationController Push, another is Model Push.
NavigationController Push:
public void Push()
{
//SecondViewController secondViewController = this.Storyboard.InstantiateViewController("SecondViewController") as SecondViewController;
SecondViewController secondViewController = new SecondViewController();
if (secondViewController!= null) {
this.NavigationController.PushViewController(secondViewController , true);
}
}
Model Push:
//SecondViewController secondViewController = this.Storyboard.InstantiateViewController("SecondViewController") as SecondViewController;
SecondViewController secondViewController = new SecondViewController();
this.PresentViewController(secondViewController , true, () => { Console.WriteLine("Push completely"); });

Related

Xamarin.Forms Google Services AdMob

I'm trying to implement AdMob in my Xamarin.Forms app (Android version for now). Here is what I have done so far:
Created a custom control, AdViewControl, in my shared project:
public class AdControlView : Xamarin.Forms.View
{
}
In my page in which to show the ad, I added the custom control in xaml:
xmlns:ads="clr-namespace:MyFeelingBuddyTwo.Views"
<ads:AdControlView BackgroundColor="Red"/>
In the Android project (AndroidManifest.xml), within :
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-myappid"/>
<activity android:name="com.google.android.gms.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>
In the Android project still, I created an AdViewRenderer:
[assembly: ExportRenderer(typeof(MyFeelingBuddyTwo.Views.AdControlView), typeof(AdViewRenderer))]
namespace MyFeelingBuddyTwo.Droid
{
class AdViewRenderer : ViewRenderer<Views.AdControlView, AdView>
{
string adUnitId = "myadunitid";
AdSize adSize = AdSize.SmartBanner;
AdView adView;
AdView CreateAdView()
{
if (adView != null)
return adView;
adView = new AdView(Forms.Context);
adView.AdSize = adSize;
adView.AdUnitId = adUnitId;
var arParams = new LinearLayout.LayoutParams(LayoutParams.WrapContent, LayoutParams.WrapContent);
adView.LayoutParameters = arParams;
adView.LoadAd(new AdRequest.Builder().Build());
return adView;
}
protected override void OnElementChanged(ElementChangedEventArgs<AdControlView> e)
{
base.OnElementChanged(e);
if(Control == null)
{
CreateAdView();
SetNativeControl(adView);
}
}
}
}
In MainActivity, intialize MobileAds just before loading the app:
MobileAds.Initialize(ApplicationContext, "ca-app-pub-appid");
When I run, I get the red background but no ads are loaded. Any ideas?
In the AdControlView class, I added :
public static readonly BindableProperty AdUnitIdProperty = BindableProperty.Create("AdUnitId", typeof(string), typeof(AdControlView));
public string AdUnitId
{
get { return (string)GetValue(AdUnitIdProperty); }
set { SetValue(AdUnitIdProperty, value); }
}
Now I can see "Test Ad" in the banner placeholder.

"Save Photos in Photo albums of iPhone or iPad using Xamarin Forms" However PCL is Deprecated

I am trying do to the thing that is the question in this Stack Overflow Post "https://stackoverflow.com/questions/49291495/save-photos-in-photo-albums-of-iphone-or-ipad-using-xamarin-forms". However in the answer for the post PCL is deprecated. What is a more updated answer? Thank you.
However in the answer for the post PCL is deprecated.
Actually , you just need to do the same thing in Share Projects . DependencyService is available in Xamarin.Forms , which you can refer https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/introduction .
in Forms
public interface ISavePhotosToAlbum
{
void SavePhotosWithStream(string name, Stream data);
}
in iOS
[assembly: Dependency(typeof(SaveToAlbum))]
namespace xxx.iOS
{
public class SaveToAlbum : ISavePhotosToAlbum
{
public void SavePhotosWithStream(string name,Stream stream)
{
var imageData = NSData.FromStream(stream);
var image = UIImage.LoadFromData(imageData);
image.SaveToPhotosAlbum((img, error) =>
{
});
}
}
}
And add the following code in info.plist
<key>NSCameraUsageDescription</key>
<string>App need to access your camera</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>App need to access your albums</string> // new in iOS 11 and later
<key>NSPhotoLibraryUsageDescription</key>
<string>App need to access your albums</string>
In addition , if you want to implement it in Android
in Android
[assembly: Dependency(typeof(SaveToAlbum))]
namespace xxx.Droid
{
public class SaveToAlbum : ISavePhotosToAlbum
{
public void SavePhotosWithStream(string name,Stream stream)
{
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
documentsPath = Path.Combine(documentsPath, "Orders", temp);
Directory.CreateDirectory(documentsPath);
string filePath = Path.Combine(documentsPath, name);
byte[] bArray = new byte[data.Length];
using (FileStream fs = new FileStream(filePath , FileMode.OpenOrCreate))
{
using (data)
{
data.Read(bArray, 0, (int)data.Length);
}
int length = bArray.Length;
fs.Write(bArray, 0, length);
}
}
}
}

Command with navigation to another page

i need to redirect to another page in ViewModel after performing some action. I have button and set my command, however if i load the page fort the first time then i get an error "Please use navigation page" application fails and i start it again and try to load the page and it works, but if i delete the app from emulator and try all over again i have the same process.
public ICommand FilterItemsCommand { get; private set; }
public FilterArticlesForPurchaseViewModel()
: base()
{
Task.Run(async () => await LoadAllDataForArticlesAndCategories()).Wait();
FilterItemsCommand = new Command(async () => await FilterItems());
}
private async Task FilterItems()
{
await Application.Current.MainPage.Navigation.PushAsync(new ArticlesForPurchaseFiltered());
}
App
MainPage = new NavigationPage(GetMainPage());
I have also tried this
Application.Current.MainPage = new NavigationPage(new ArticlesForPurchaseFiltered());
But then i cant go back to previous page and if i use android back button the application fails
BTW i am using master detail
You can add INavigation navigation to your ViewModel's constructor like following code.
public ItemsViewModel(INavigation navigation)
{
Title = "Browse";
Items = new ObservableCollection<Item>();
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
FilterItemsCommand = new Command(() => { navigation.PushModalAsync(new Page1()); });
MessagingCenter.Subscribe<NewItemPage, Item>(this, "AddItem", async (obj, item) =>
{
var newItem = item as Item;
Items.Add(newItem);
await DataStore.AddItemAsync(newItem);
});
}
When you binding the viewmodel, you can add the attribute like following code.
public ItemsPage()
{
InitializeComponent();
BindingContext = viewModel = new ItemsViewModel(Navigation);
}
If you want to achieve the navigation in the viewModel, you can use
// this way you need add `MainPage =new NavigationPage( new MainPage());` in app.xaml.cs
navigation.PushAsync(new Page1());
// this way you do not need `MainPage =new NavigationPage( new MainPage());` in //app.xaml.cs, just used it directly
navigation.PushModalAsync(new Page1());

Getting navigation bar height in dependency service - Xamarin Forms

i have this issue wherein i need to get the navigation bar height in my Dependency Service.
Currently I am stuck on what to follow here. I tried everything i find in stackoverflow and google but no one works for me.
Heres my code:
[assembly: Dependency(typeof(DeviceInfo))]
namespace Wicket.App.Mobile.iOS.Framework
{
public class DeviceInfo : IDeviceInfo
{
public float StatusBarHeight => (float)UIApplication.SharedApplication.StatusBarFrame.Size.Height;
public float NavigationBarHeight => GetNavigationBarHeight();
public static UINavigationController NavigationController { get; set; }
public float GetNavigationBarHeight()
{
//Get navigation bar height
return 0;
}
}
}
I already completed the android part and it works good. The only problem now is in iOS. I have tried getting the instance of navigationcontroller in AppDelegate so that I can just get the bar frame like this NavigationBar.Bounds.Height;
I think this should work:
var navheight = GetTopViewController().NavigationController.NavigationBar.Frame.Height;
public static UIViewController GetTopViewController()
{
var window = UIApplication.SharedApplication.KeyWindow;
var vc = window.RootViewController;
while (vc.PresentedViewController != null)
vc = vc.PresentedViewController;
if (vc is UINavigationController navController)
vc = navController.ViewControllers.Last();
return vc;
}
Solution:
How about pass an instance of viewController as parameter in the function inside the IDeviceInfo?
Try this:
public void getNaviHeight(ContentPage vc)
{
var renderer = Platform.GetRenderer(vc);
if (renderer == null)
{
renderer = RendererFactory.GetRenderer(vc);
Platform.SetRenderer(vc, renderer);
}
var viewController = renderer.ViewController;
var h = viewController.NavigationController?.NavigationBar.Frame.Height;
}
And use the dependency:
public MainPage ()
{
DependencyService.Get<IDeviceInfo>().getNaviHeight(this);
}
this worked to me:
var navigationBar = UIApplication.SharedApplication.KeyWindow.RootViewController.View.Subviews[0].Subviews.OfType<UINavigationBar>().FirstOrDefault();
if(navigationBar != null)
{
// continue here...
}

Xamarin.Forms and Plugin.Media: after about 20 photos something crashes

I have a problem with Xamarin.Forms ver. 2.3.4.224 and Plugin.Media ver. 2.6.2. The problem occurs after taking about 20 photos (depends from the device): basically the app crashes without any apparently reason.
If you want to replicate the error, I created a test project for you on GitHub. With my iPad Air or iPad Pro after about 30 photos (video iPad Air - iPad Pro). All devices are iOS ver. 10.3.1 and they have enough space to storage photos.
The app is very simple: you have two buttons one for taking a picture and the other one to pick a photo. If you take photos one after another, after about 20 (32 in an iPad Air) the app crashes. I'm just take photos with the Plugin.Media nothing more.
Any ideas are welcome.
Update
In my project I had a reference to Refractored.MvvmHelpers and I noticed if I remove it, I can take more pictures. I created my BaseViewModel with INotifyPropertyChanged and I noticed I can take more photos.
I created then a new project (you can find it on GitHub under cameratesteasy) without MVVM and there is just the code to take a photo like:
public partial class cameratesteasyPage : ContentPage
{
int count = 0;
public cameratesteasyPage()
{
InitializeComponent();
CrossMedia.Current.Initialize();
}
void UpdateCount()
{
count++;
CountLabel.Text = $"{count} times";
}
async void StartCameraTapped(object sender, System.EventArgs args)
{
using (var file = await CrossMedia.Current.TakePhotoAsync(
new StoreCameraMediaOptions {}))
{
if (file == null)
return;
UpdateCount();
}
}
async void StartCameraTakeTapped(object sender, System.EventArgs args)
{
var file = await CrossMedia.Current.PickPhotoAsync();
if (file == null)
return;
UpdateCount();
}
}
In this case the app shut down after 52 photos. I saved the log for Xcode and you can see it here.
I used Xamarin Profile and the memory level is always low. After about 30 photos, an error occurs in Xamarin Profiler
Finally I could create a Xamarin Profiler file
Also I noticed this kind of error occurs on iPads. The same app in an iPhone is working fine (apparently) or I didn't find up to now the number of photos before crashing.
Update /2
I decided to implement a native function for taking photo.
Interface
public interface ICamera
{
void TakePicture();
}
Implementation
using System;
using cameratest.iOS;
using Foundation;
using UIKit;
using Xamarin.Forms;
[assembly: Xamarin.Forms.Dependency(typeof(Camera_iOS))]
namespace cameratest.iOS
{
public class Camera_iOS : ICamera
{
static UIImagePickerController picker;
static Action<NSDictionary> _callback;
static void Init()
{
if (picker != null)
return;
picker = new UIImagePickerController();
picker.Delegate = new CameraDelegate();
}
class CameraDelegate : UIImagePickerControllerDelegate
{
public override void FinishedPickingMedia(
UIImagePickerController picker, NSDictionary info)
{
var cb = _callback;
_callback = null;
picker.DismissModalViewController(true);
cb(info);
}
}
public static void TakePicture(UIViewController parent,
Action<NSDictionary> callback)
{
Init();
picker.SourceType = UIImagePickerControllerSourceType.Camera;
_callback = callback;
parent.PresentModalViewController(picker, true);
}
public static void SelectPicture(UIViewController parent,
Action<NSDictionary> callback)
{
Init();
picker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
_callback = callback;
parent.PresentModalViewController(picker, true);
}
public void TakePicture()
{
var rc = UIApplication.SharedApplication.KeyWindow.RootViewController;
TakePicture(rc, (obj) =>
{
var photo = obj.ValueForKey(
new NSString("UIImagePickerControllerOriginalImage")) as UIImage;
var documentsDirectory =
Environment.GetFolderPath(Environment.SpecialFolder.Personal);
// hardcoded filename, overwritten each time
string jpgFilename = System.IO.Path.Combine(documentsDirectory,
"Photo.jpg");
NSData imgData = photo.AsJPEG();
NSError err = null;
if (imgData.Save(jpgFilename, false, out err))
{
Console.WriteLine("saved as " + jpgFilename);
}
else
{
Console.WriteLine("NOT saved as " +
jpgFilename + " because" + err.LocalizedDescription);
}
});
}
}
}
With this code after about 30 photos, the app crashes. The only difference is with this code I can receive some alert from ReceiveMemoryWarning. If you have an interest, I updated the code on GitHub.

Resources