Xamarin Forms Orientation on iPad - xamarin.forms

I have a Universal Xamarin Forms App with a single page wrapped in a NavigationPage:
Current.MainPage = new NavigationPage(new RootPage()
{
BackgroundColor = (Color)Application.Current.Resources["BackgroundColour"]
})
{
BackgroundColor = (Color)Application.Current.Resources["BackgroundColour"],
BarBackgroundColor = (Color)Application.Current.Resources["BackgroundColour"],
Padding = NavigationPaddingForPlatfrom()
};
I've also overridden GetSupportedInterfaceOrientations in AppDelegate and set a break point - however the break point is never hit. When I rotate in the simulator or device, the break point isn't hit. I've also set the Device Orientation in info.plist to Portrait only, however the App still rotates.
Am I missing some configuration point that's needed to control orientation?
I'm using Xamarin Forms 2.4.0.38779.
The end goal is to force a MasterDetail Page into landscape only.

For forcing exact mode this code worked for me:
public MainPage()
{
InitializeComponent();
OnOrientationChanged += OnOrientationChange;
OnOrientationChange(this, new OrientationChangedEventArgs(DeviceOrientation.Landscape));
}
private void OnOrientationChange(object sender, OrientationChangedEventArgs e)
{
IOrientationService orientationService = DependencyService.Get<IOrientationService>();
DeviceOrientation currentOrientation = orientationService.GetCurrentOrientation();
if (currentOrientation != DeviceOrientation.Landscape)
{
orientationService.SetCurrentOrientation(DeviceOrientation.Landscape);
}
}

Have you tried this.
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
if (width != this.width || height != this.height)
{
this.width = width;
this.height = height;
if (Width > Height)
{
//your grid
}
else
{
//your grid
}
}
}

After reading a lot of article and forum posts, I came across this:
https://forums.xamarin.com/discussion/79389/how-to-lock-orientation-in-landscape-for-an-ipad-only-app
The last post by JoeRaco references this SO post:
Xcode 7 ERROR ITMS-90474: "Invalid Bundle", can't submit to Apple
Without 'Requires full screen' set to true, GetSupportedInterfaceOrientations was not being called in AppDelegate. Therefore adding the following to the info.plist solved my problem:
<key>UIRequiresFullScreen</key>
<true/>

Related

Xamarin Forms UWP specifying button width request with an effect

I would like to specify the width of a Xamarin.Forms.Button with an effect in UWP, something like:
protected override void OnAttached()
{
if (VisualElement is Xamarin.Forms.Button buttonControl)
{
buttonControl.WidthRequest = 40;
buttonControl.BorderWidth = 1;
}
}
VisualElement is an invalid type. What goes in its place? Thank you!
Xamarin Forms UWP specifying button width request with an effect
In Xamarin effect class, the attached control is referenced with Element property but not VisualElement, please edit your code like the following and you will get forms button on OnAttached method.
protected override void OnAttached()
{
if (Element is Xamarin.Forms.Button buttonControl)
{
buttonControl.WidthRequest = 40;
buttonControl.BorderWidth = 1;
}
}

HOWTO: Manipulate Back Arrow Icon and Button on Navigation Bar (Xamarin Forms / Android)

I am attempting to change the size of the back arrow in the navigation bar.
Using information from this article, I have added the following code:
protected override Task<bool> OnPushAsync(Page view, bool animated)
{
var result = base.OnPushAsync(view, animated);
var activity = (Activity) Context;
var toolbar = activity.FindViewById<Toolbar>(Resource.Id.toolbar);
if (toolbar != null)
{
if (toolbar.NavigationIcon != null)
{
if (toolbar.NavigationIcon is DrawerArrowDrawable navigationIcon)
{
// Code goes here?
}
}
}
return result;
}
If this is indeed the correct path, what code goes in the area marked by the comment "Code goes here?"?
* UPDATE *
I realized that what I am trying to figure out was not exactly described in my original question.
More specifically, when I mentioned that I am trying to resize the navigation bar back arrow, what I am really trying to do is to resize the button that the icon appears on.
For example, if I shrink the height of the navigation bar using code like the following:
On<Android>().SetBarHeight(100);
The button that the icon appears on will be clipped.
Ultimately, what I am trying to accomplish is resizing the icon AND the button that the icon appears on. I have already figured out how to do the former.
I am attempting to change the size of the back arrow in the navigation bar.
If you want to change size of the back button in the navigation bar, you can get new icon from Drawable in resource for toolbar.NavigationIcon.
public class NavigationPageRenderer : Xamarin.Forms.Platform.Android.AppCompat.NavigationPageRenderer
{
public AppCompToolbar toolbar;
public Activity context;
protected override Task<bool> OnPushAsync(Page view, bool animated)
{
var retVal = base.OnPushAsync(view, animated);
context = (Activity)Forms.Context;
toolbar = context.FindViewById<AppCompToolbar>(Droid.Resource.Id.toolbar);
if (toolbar != null)
{
if (toolbar.NavigationIcon != null)
{
if (toolbar.NavigationIcon is DrawerArrowDrawable navigationIcon)
{
// Code goes here?
toolbar.NavigationIcon = Android.Support.V7.Content.Res.AppCompatResources.GetDrawable(context, Resource.Drawable.back);
toolbar.Title = "Back";
}
}
}
return retVal;
}
}
Here is the sample you can take a look:
https://github.com/hachi1030-Allen/XamarinCustomNavBar
<NavigationPage.TitleView> will help you out there. This is a XAML approach.
Example:
<NavigationPage.TitleView>
<StackLayout>
....
</StackLayout>
</NavigationPage.TitleView>
Using this approach you will be able to set HeightRequest and WidthRequest of whatever element you place inside the StackLayout and whatever else you want to amend.
Also, note that if you are having icon size problems it may be worth looking into whether or not your drawable/ icons are the right size for the right resolution.

xamarin.forms - hide components on rotation

In Xamarin.Forms, when the phone is rotated I want to hide certain XAML components. I can't seem to find anything available from xamarin simple to use... can someone point me in the right direction?
thank you
Within a Xamarin.Forms Page, you could subscribe to the SizeChanged event or override the OnSizeAllocated method. There is some good documentation that describes both options. Below is an example of using OnSizeAllocated:
private double width = 0;
private double height = 0;
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height); //must be called
if (this.width != width || this.height != height)
{
this.width = width;
this.height = height;
if (this.width > this.height)
{
// reconfigure for landscape
}
else
{
// reconfigure for portrait
}
}
}

How to make Xamarin.Forms.Editor scrollable/auto resizable?

I have an scrollabe layout with an Editor inside that I'd like to make scrollable or auto resizable to fit the contents.
I can't find how to do it.
I tried a custom renderer but I can't find how to set InputMethods to the Control.
Any ideas?
With the help of this post: https://forums.xamarin.com/discussion/80360/editor-inside-scrollview-not-scrolling
That fixed the scrolling on Android (iOS works by default). It avoids the parent scroll event when touching inside the Editor, triggering only the Editor scroll.
First a class on Android project:
using Android.Views;
namespace MyApp.Droid
{
public class DroidTouchListener : Java.Lang.Object, View.IOnTouchListener
{
public bool OnTouch(View v, MotionEvent e)
{
v.Parent?.RequestDisallowInterceptTouchEvent(true);
if ((e.Action & MotionEventActions.Up) != 0 && (e.ActionMasked & MotionEventActions.Up) != 0)
{
v.Parent?.RequestDisallowInterceptTouchEvent(false);
}
return false;
}
}
}
And then use it on the Android Custom EditorRenderer:
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
var nativeEditText = (global::Android.Widget.EditText)Control;
//While scrolling inside Editor stop scrolling parent view.
nativeEditText.OverScrollMode = OverScrollMode.Always;
nativeEditText.ScrollBarStyle = ScrollbarStyles.InsideInset;
nativeEditText.SetOnTouchListener(new DroidTouchListener());
//For Scrolling in Editor innner area
Control.VerticalScrollBarEnabled = true;
Control.MovementMethod = ScrollingMovementMethod.Instance;
Control.ScrollBarStyle = Android.Views.ScrollbarStyles.InsideInset;
//Force scrollbars to be displayed
Android.Content.Res.TypedArray a = Control.Context.Theme.ObtainStyledAttributes(new int[0]);
InitializeScrollbars(a);
a.Recycle();
}
}

How to prevent a component from being dragged out of the stage in Flex 3

I think there is a simple solution to this question, just not simple enough for me to find it.
Question:
How do you constrain a TitleWindow in Flex 3 from being dragged off the screen/stage? Is there a way to restrict the TitleWindow to the viewing area?
Example: Let's say I have an application that take 100% of the screen. Next, I create a TitleWindow via the PopUpManager. I can then proceed to click and hold (drag) that window off the screen, then release the mouse button. That window is now lost off-screen somewhere. Is there a way to keep the window from being dragged beyond the viewing area?
Thanks for the help in advance.
this is a very old post, but here's another way of doing it:
Whether you are extending the component or not, in the TitleWindow definition add the following line: move:"doMove(event)"
Import the Application library (import mx.core.Application;)
and add the doMove function:
private function doMove(event:Event):void
{//keeps TW inside layout
var appW:Number=Application.application.width;
var appH:Number=Application.application.height;
if(this.x+this.width>appW)
{
this.x=appW-this.width;
}
if(this.x<0)
{
this.x=0;
}
if(this.y+this.height>appH)
{
this.y=appH-this.height;
}
if(this.y<0)
{
this.y=0;
}
}
For flex 4 the answer is here: http://blog.flexexamples.com/2010/01/20/constraining-the-movement-on-a-spark-titlewindow-container-in-flex-4/
You can set its isPopUp property to false to prevent it from being dragged in the first place.
var popupWin:TitleWindow = PopUpManager.createPopUp(this, TitleWindow);
PopUpManager.centerPopUp(popupWin);
popupWin.isPopUp = false;
I don't know if the DragManager class in flex supports bounds checking, but if you really want to allow dragging but limit its bounds, you can still set isPopUp to false and implement the dragging code yourself so that the component never goes outside the limits specified by you. Check startDrag() method for an example. Bounds rectangle is the key.
Flex 4
<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
windowMoving="windowMovingHandler(event)">
.
.
.
protected function windowMovingHandler(event:TitleWindowBoundsEvent):void
{
var appBounds:Rectangle = parentApplication.getBounds(DisplayObject(parentApplication));
if(!appBounds.containsRect(event.afterBounds)){
event.preventDefault();
}
}
// for better precision, corect appBounds manualy, or, instead of "parentApplication.getBounds..." create new rectangle of your application size
Subclass the TitleWindow and add a canvas over the title bar as a drag proxy. Then you can explicity call startDrag with a boundary rectangle.
This is pretty skeletal, but should put you on the path...
The reason for the proxy is you may get some weird behavior when you click the titleBar label if you don't have the canvas over it.
public class MyTitleWindow extends TitleWindow
{
public var titleBarOverlay:Canvas;
override protected function createChildren():void
{
super.createChildren();
if(!titleBarOverlay)
{
titleBarOverlay = new Canvas();
titleBarOverlay.width = this.width;
titleBarOverlay.height = this.titleBar.height;
titleBarOverlay.alpha = 0;
titleBarOverlay.setStyle("backgroundColor", 0x000000);
rawChildren.addChild(titleBarOverlay);
}
addListeners();
}
override protected function updateDisplayList(w:Number, h:Number):void
{
super.updateDisplayList(w, h);
titleBarOverlay.width = this.width;
titleBarOverlay.height = this.titleBar.height;
}
private function addListeners():void
{
titleBarOverlay.addEventListener(MouseEvent.MOUSE_DOWN, onTitleBarPress, false, 0, true);
titleBarOverlay.addEventListener(MouseEvent.MOUSE_UP, onTitleBarRelease, false, 0, true);
}
private function onTitleBarPress(event:MouseEvent):void
{
// Here you can set the boundary using owner, parent, parentApplication, etc.
this.startDrag(false, new Rectangle(0, 0, parent.width - this.width, parent.height - this.height));
}
private function onTitleBarRelease(event:Event):void
{
this.stopDrag();
}
}
You could simply override the move function and prevent "illegal" movement (it is called internally by the Panel drag management).
I think that you also should listen on stage resize, because reducing it (e.g. if the user resize the browser window) could send your popup out of stage even without actually moving it.
public class MyTitleWindow extends TitleWindow {
public function MyTitleWindow() {
// use a weak listener, or remember to remove it
stage.addEventListener(Event.RESIZE, onStageResize,
false, EventPriority.DEFAULT, true);
}
private function onStageResize(event:Event):void {
restoreOutOfStage();
}
override public function move(x:Number, y:Number):void {
super.move(x, y);
restoreOutOfStage();
}
private function restoreOutOfStage():void {
// avoid the popup from being positioned completely out of stage
// (use the actual width/height of the popup instead of 50 if you
// want to keep your *entire* popup on stage)
var topContainer:DisplayObjectContainer =
Application.application.parentDocument;
var minX:int = 50 - width;
var maxX:int = topContainer.width - 50;
var minY:int = 0;
var maxY:int = topContainer.height - 50;
if (x > maxX)
x = maxX
else if (x < minX)
x = minX;
if (y > maxY)
y = maxY
else if (y < minY)
y = minY;
}
}
In your TitleWindow's creationComplete handler add the following:
this.moveArea.visible=false;
This will do the job.
On the other hand, if you have a custom skin, you can remove the "moveArea" part. This should work, too.

Resources