Xamarin I updated to version 4, Forms and 2.0 versions. On Android, I use AppCompat.
I had a problem. Previously, the Android keyboard caused resize view. Now this does not happen. The keyboard appears on the top view. And the desired Elements to be hiding.
I've tried:
[Activity(WindowSoftInputMode = SoftInput.AdjustResize, Label = "Title", Icon = "#drawable/icon", Theme = "#style/MyTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
ToolbarResource = Resource.Layout.toolbar;
TabLayoutResource = Resource.Layout.tabs;
LoadApplication(new App());
Window.DecorView.SetFitsSystemWindows(true);
}
}
Daylight AppCompat has been made on this lesson: https://blog.xamarin.com/material-design-for-your-xamarin-forms-android-apps/
Thank you.
I have solved the problem. Decompile class
"Forms AppCompatActivity" and watched how the method works OnCreate.
As a result, I turned out the following code:
[Activity(Label = "Title", Icon = "#drawable/icon", Theme = "#style/MyTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
Window.SetSoftInputMode(SoftInput.AdjustResize);
AndroidBug5497WorkaroundForXamarinAndroid.assistActivity(this);
ToolbarResource = Resource.Layout.toolbar;
TabLayoutResource = Resource.Layout.tabs;
LoadApplication(new App());
}
public class AndroidBug5497WorkaroundForXamarinAndroid
{
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
// CREDIT TO Joseph Johnson (http://stackoverflow.com/users/341631/joseph-johnson) for publishing the original Android solution on stackoverflow.com
public static void assistActivity(Activity activity)
{
new AndroidBug5497WorkaroundForXamarinAndroid(activity);
}
private Android.Views.View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private AndroidBug5497WorkaroundForXamarinAndroid(Activity activity)
{
FrameLayout content = (FrameLayout)activity.FindViewById(Android.Resource.Id.Content);
mChildOfContent = content.GetChildAt(0);
ViewTreeObserver vto = mChildOfContent.ViewTreeObserver;
vto.GlobalLayout += (object sender, EventArgs e) => {
possiblyResizeChildOfContent();
};
frameLayoutParams = (FrameLayout.LayoutParams)mChildOfContent.LayoutParameters;
}
private void possiblyResizeChildOfContent()
{
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious)
{
int usableHeightSansKeyboard = mChildOfContent.RootView.Height;
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
frameLayoutParams.Height = usableHeightSansKeyboard - heightDifference;
mChildOfContent.RequestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight()
{
Rect r = new Rect();
mChildOfContent.GetWindowVisibleDisplayFrame(r);
if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop)
{
return (r.Bottom - r.Top);
}
return r.Bottom;
}
}
}
It is important to add "Window.SetSoftInputMode(SoftInput.AdjustResize);" After calling base.OnCreate(bundle);
Related
Is there a standard cross platform way of playing a 250 ms or so 'ding' on Xamarin Forms iOS and Android?
Mark Wardell
You can use DependencyService to play default system notification sound in each platform .
Create IPlaySoundService Interface :
public interface IPlaySoundService
{
void PlaySystemSound();
}
Implement the PlaySystemSound method in iOS as follow:
[assembly: Xamarin.Forms.Dependency(typeof(PlaySoundService))]
namespace AppCarouselViewSample.iOS
{
public class PlaySoundService : IPlaySoundService
{
public void PlaySystemSound()
{
var sound = new SystemSound(1000);
sound.PlaySystemSound();
}
}
}
Implement the PlaySystemSound method in Android as follow :
[assembly:Xamarin.Forms.Dependency(typeof(PlaySoundService))]
namespace AppCarouselViewSample.Droid
{
public class PlaySoundService : IPlaySoundService
{
public void PlaySystemSound()
{
Android.Net.Uri uri = RingtoneManager.GetDefaultUri(RingtoneType.Ringtone);
Ringtone rt = RingtoneManager.GetRingtone(MainActivity.instance.ApplicationContext, uri);
rt.Play();
}
}
}
This is the definition of instance from MainActivity :
namespace xxx.Droid
{
[Activity(Label = "AppCarouselViewSample", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity instance { set; get; }
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
instance = this;
Xamarin.Forms.Forms.SetFlags(new string[] { "CarouselView_Experimental", "SwipeView_Experimental", "IndicatorView_Experimental" });
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
...
}
Then it they will play the default notification Sound in each platform . You can modify SystemSoundID in iOS to fit your wants .Here is the Sound ID list .
here is my now compiling yet crashing Droid implementation
using Android.Media;
using TripCalculator.Droid.Services;
[assembly: Xamarin.Forms.Dependency(typeof(PlaySoundService))]
// Crashes
namespace TripCalculator.Droid.Services
{
public class PlaySoundService : IPlaySoundService
{
public void PlaySystemSound()
{
var currentContext = Android.App.Application.Context;
Android.Net.Uri uri = RingtoneManager.GetDefaultUri(RingtoneType.Ringtone);
Ringtone rt = RingtoneManager.GetRingtone(currentContext.ApplicationContext, uri);
rt.Play();
}
}
}
I've found this: How to download image and save it in local storage using Xamarin-Forms.?
This partially adresses my problem except for two points:
I'd need to download the image to the gallery, not the apps'path
I need this to work for both, android and IOs. This seems to only work for Android.
Basically i know the URL of a file online, and need to download it to the gallery. It would be great if ic ould "save" it from inside the application, instead of "downloading". It would be nice if the client cant figure out the URL of the images he wants to save.
EDIT:
Now I am using FFImageLoading.. here is my current (not working) code..
private async void SaveToGallery_Clicked(object sender, EventArgs e)
{
var img = await MyImage.GetImageAsJpgAsync(quality: 100);
string fileName = uri.ToString().Split('/').Last();
DependencyService.Get<IMediaService>().SaveImageFromByte(img, fileName);
}
Android MediaService.cs
[assembly: Xamarin.Forms.Dependency(typeof(MediaService))]
namespace GalShare.Droid
{
public class MediaService : IMediaService
{
Context CurrentContext => CrossCurrentActivity.Current.Activity;
public void SaveImageFromByte(byte[] imageByte, string fileName)
{
try
{
Java.IO.File storagePath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures);
string path = System.IO.Path.Combine(storagePath.ToString(), fileName);
System.IO.File.WriteAllBytes(path, imageByte);
var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(path)));
CurrentContext.SendBroadcast(mediaScanIntent);
}
catch (Exception ex)
{
}
}
}
}
Android MainActivity.cs:
namespace GalShare.Droid
{
[Activity(Label = "GalShare", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public int STORAGE_PERMISSION_CODE = 101;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
FFImageLoading.Forms.Platform.CachedImageRenderer.Init(enableFastRenderer: false);
base.OnCreate(savedInstanceState);
Forms.SetFlags("CollectionView_Experimental");
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
CachedImageRenderer.InitImageViewHandler();
string fileName = "galleries.db3";
string folderPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
string completePath = Path.Combine(folderPath, fileName);
checkPermission("android.permission.write_external_storage", STORAGE_PERMISSION_CODE);
LoadApplication(new App(completePath));
}
public void checkPermission(String permission, int requestCode)
{
var thisActivity = Android.App.Application.Context as Activity;
// Checking if permission is not granted
if (ContextCompat.CheckSelfPermission(
Android.App.Application.Context,
permission)
== Android.Content.PM.Permission.Denied)
{
RequestPermissions(new String[] { Manifest.Permission.WriteExternalStorage }, requestCode);
}
else
{
}
}
}
}
Initialilzing CrossCurrentActivity in the MainActivity.cs solved the problem:
CrossCurrentActivity.Current.Init(this, bundle);
Runtime error when I try to change ringer mode to normal.i am using dependency service to call audio manager in android in xamarin form but code runs without error when the ringer mode change to silent ( maybe it's already silent)
About changing ringer mode, you can follow these steps.
1.define a interface in Xamarin.Forms PCL.
public interface IChangeRingModeService
{
void changeRingModeToNormal();
void changeRingModeToVibrate();
void changeRingModeToSilent();
}
In Android project, implement this interface in Mainactivity.cs, please don't forget register dependency
[assembly: Dependency(typeof(MainActivity))]
namespace App4.Droid
{
[Activity(Label = "App4", Icon = "#mipmap/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize| ConfigChanges.Orientation)]
public class MainActivity :
global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IChangeRingModeService
{
AudioManager am;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
public void changeRingModeToVibrate()
{
am = (AudioManager)Android.App.Application.Context.GetSystemService(Context.AudioService);
am.RingerMode = RingerMode.Vibrate;
}
public void changeRingModeToNormal()
{
am = (AudioManager)Android.App.Application.Context.GetSystemService(Context.AudioService);
am.RingerMode = RingerMode.Normal;
}
public void changeRingModeToSilent()
{
am = (AudioManager)Android.App.Application.Context.GetSystemService(Context.AudioService);
am.RingerMode = RingerMode.Silent;
}}}
call this method in click event.
private void Button1licked(object sender, EventArgs e)
{
DependencyService.Get<IChangeRingModeService>().changeRingModeToVibrate();
}
private void Button2licked(object sender, EventArgs e)
{
DependencyService.Get<IChangeRingModeService>().changeRingModeToNormal();
}
private void Button3licked(object sender, EventArgs e)
{
DependencyService.Get<IChangeRingModeService>().changeRingModeToSilent();
}
I created simple Xamarin.Forms Bluetooth low energy scanning application. As I will use Bluetooth only on Android, I implemented scanning in MainActivity.cs of Android project:
namespace BlankAppXamlXamarinForms.Droid
{
[Activity(Label = "BlankAppXamlXamarinForms", Icon = "#drawable/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
private BluetoothManager _manager;
App app;
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
app = new App();
var appContext = Application.Context;
_manager = (BluetoothManager)appContext.GetSystemService(BluetoothService);
_manager.Adapter.BluetoothLeScanner.StartScan(new MyScanCallback(app));
LoadApplication(new App());
}
}
public class MyScanCallback : ScanCallback
{
App _app;
public MyScanCallback(App app) {
_app = app;
}
public override void OnScanResult(ScanCallbackType callbackType, ScanResult result)
{
_app.newDevice(result.Device.Name + " - " + result.Device.Address);
}
}
}
The problem is that OnScanResult receives advertising packets only a moment after the application is started and when I switch the display of my phone off and then turn it on again. Meanwhile the application receives almost no advertising packets. How to receive advertising packets all the time my application is active?
You are creating two instances of App. Instead of LoadApplication(new App()); you should be passing in your field app, i.e. LoadApplication(app);
Also, instead of starting the scan in OnCreate, you might want to start the scan in OnResume and stop the scan in OnPause e.g.:
public class MainActivity : FormsAppCompatActivity
{
BluetoothManager bleManager;
App app;
ScanCallback scanCallback;
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
Forms.Init(this, bundle);
app = new App();
bleManager = (BluetoothManager)Application.Context.GetSystemService(BluetoothService);
scanCallback = new MyScanCallback(app);
LoadApplication(new App());
}
protected override void OnResume()
{
base.OnResume();
bleManager.Adapter.BluetoothLeScanner.StartScan(scanCallback);
}
protected override void OnPause()
{
base.OnPause();
bleManager.Adapter.BluetoothLeScanner.StopScan(scanCallback);
}
}
A black screen with app title is showing when minimizing the app while loading splash screen , also the first screen will display after some time. Here is my splash activity and main activity classes.
[Activity(Theme = "#style/Theme.Splash", Icon = "#drawable/icon", MainLauncher = true, NoHistory = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Behind)]
public class SplashActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
var dpWidth = Resources.DisplayMetrics.WidthPixels/Resources.DisplayMetrics.Density;
RequestedOrientation = dpWidth > 700 ? ScreenOrientation.Unspecified : ScreenOrientation.Portrait;
ThreadPool.QueueUserWorkItem(o => LoadActivity());
}
private void LoadActivity()
{
RunOnUiThread(() => StartActivity(typeof(MainActivity)));
}
public override void OnBackPressed()
{
Environment.Exit(0);
}
}
[Activity(Label = "HACCP", ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : FormsApplicationActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
ActionBar.SetIcon(Android.Resource.Color.Transparent);
Forms.Init(this, bundle);
// some function //
LoadApplication(new App());
}
}
You tagged Xamarin.Forms so it should be as simple as..
class App : Application
{
public App()
{
MainPage = new MySplashPage();
}
}
class MySplashPage : ContentPage
{
public MySplashPage()
{
Task.Delay(3000); //show my pretty splash for 3 seconds
Application.Current.MainPage = new MyOtherSpiffyPage();
}
}
Not certain if the activity attribute ScreenOrientation = ScreenOrientation.Behind) is causing any issues, we don't use that in our apps.
Here is a "standard" splash activity we do use, letting Xamarin.Android take care of timing etc:
public class SplashActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Start main.
StartActivity(typeof(MainActivity));
}
}
You might try simplifying your app in similar fashion.