I have two Buttons on top of my screen .. Button A and Button B.. ByDefault button A will be selected and below that a view with all details related to Button A. When user clicks on Button B , the view will move to left and new view having the details related to button B will come from right with fade in and fade out animation...
Current Status- I am able to change the View on Button Click by hiding one and unhiding other.. But I am stuck with Animation..
Can You Please help me out.
You can use a parent/child-based Animation to control the slide and fade and have them properly sync'd
void RunAnim(Color disableColor, Color backgroundColor, bool disable)
{
new Animation
{
{ 0, 1, new Animation (v => view1.Opacity = v, disable ? 1 : 0, disable ? 0 : 1) },
{ 0, 1, new Animation (v => view1.TranslationX = v, disable ? 0 : -view1.Width, disable ? -view1.Width : 0) },
{ 0, 1, new Animation (v => view2.TranslationX = v, disable ? view1.Width : 0, disable ? 0 : view1.Width) },
{ 0, 1, new Animation (v => view2.Opacity = v, disable ? 0 : 1, disable ? 1 : 0) },
}.Commit(this, "viewAnim", 16, 1000, Easing.CubicInOut, (v, c) =>
{
physicalButton.IsEnabled = !disable;
physicalButton.BackgroundColor = disableColor;
networkButton.IsEnabled = disable;
networkButton.BackgroundColor = backgroundColor;
});
}
void Physical_Clicked(object sender, EventArgs e)
{
var disableColor = Color.Navy;
var backgroundColor = Color.Transparent;
var disable = true;
RunAnim(disableColor, backgroundColor, disable);
}
void Network_Clicked(object sender, EventArgs e)
{
var disableColor = Color.Transparent;
var backgroundColor = Color.Navy;
var disable = false;
RunAnim(disableColor, backgroundColor, disable);
}
Note: The gif looks janky, but the animation is smooth...
First, in your page
private readonly ScreenMetrics _metrics;
private readonly int _formsWidth;
private readonly int _formsHeight;
public MainPage()
{
InitializeComponent();
//calculate screen size, to use in animations
_metrics = DeviceDisplay.ScreenMetrics;
_formsWidth = Convert.ToInt32(_metrics.Width / _metrics.Density);
_formsHeight = Convert.ToInt32(_metrics.Height / _metrics.Density);
}
In OnAppearing, translate the elements you want outside the screen
protected override async void OnAppearing()
{
base.OnAppearing();
await Task.WhenAll(
//translate to the left side of the device, negative
YourViewLeftSide.TranslateTo(_formsWidth, 0, 0, null),
//translate to the right side of the device, negative
YourViewRightSide.TranslateTo(-_formsWidth, 0, 0, null)
);
}
On the button that animates left view
async void OnButton1Clicked(object sender, EventArgs args)
{
//animate left side
YourViewLeftSide.TranslateTo(0, 0, 400, Easing.CubicInOut),
}
On the button that animates right view
async void OnButton2Clicked(object sender, EventArgs args)
{
//animate right side
YourViewRightSide.TranslateTo(0, 0, 400, Easing.CubicInOut),
}
Now you can adapt and customize to your needs!
Finally I used CarouselView to achieve this Functionality
Related
We have discovered in our Xamarin app in iOS 13 that the disclosure button action is not firing. Our basic code looks like this in a GridCell Class. It had been firing in iOS 12. Is there another event delegate in iOS 13?
[EventDelegate("accessorySelected")]
public event EventHandler AccessorySelected
{
add
{
accessorySelected += value;
SetAccessory();
}
remove
{
accessorySelected -= value;
SetAccessory();
}
}
private event EventHandler accessorySelected;
private void SelectAccessory(object sender, EventArgs args)
{
var handler = accessorySelected;
if (handler != null)
{
handler(Pair ?? this, EventArgs.Empty);
}
else
{
... Action Code ....
}
}
Delving into this code, it was not what was expected. It actually dates from 2011 and the code to load the disclosure event was unconventional, or as another one of our developers called it during this review, "Anti-pattern".
public class GridCell : UITableViewCell, INotifyPropertyChanged
{
...
public override void LayoutSubviews()
{
base.LayoutSubviews();
// I do not like going off of the frame width. The ContentView frame width would be preferred,
// but we would first need to ensure that its value is correctly adjusted in case of a disclosure.
// This should happen automatically, but it doesn't always happen in time for PerformLayout.
// There also seem to be cases where the adjusted value is not entirely accurate.
float width = (float)Frame.Width;
if (UIDevice.CurrentDevice.CheckSystemVersion(7, 0))
{
width -= (Accessory == UITableViewCellAccessory.DetailDisclosureButton ? 67 :
Accessory == UITableViewCellAccessory.DisclosureIndicator ? 33 : 0);
}
else
{
width -= (Accessory == UITableViewCellAccessory.DetailDisclosureButton ? 33 :
Accessory == UITableViewCellAccessory.DisclosureIndicator ? 20 : 0);
}
width = Math.Max(width, 0);
var size = this.PerformLayout(new iFactr.UI.Size(width, Math.Max(MinHeight - 1, 0)), new iFactr.UI.Size(width, Math.Max(MaxHeight - 1, 0)));
ContentView.Frame = new CGRect(0, 0, (float)size.Width, (float)size.Height);
Frame = new CGRect(Frame.Location, new CGSize(Frame.Width, ContentView.Frame.Height));
// Checking subview for Disclosure - iOS 13 changed 2019 subview
var disclosure = this.GetSubview<UIControl>(c => c.Description.StartsWith("<UITableViewCellDetailDisclosureView") || c.Description.StartsWith("<UIButton"));
var dlog = this.GetSubview<UIControl>();
if (disclosure != null)
{
//Setting Disclosure button (i) event
disclosure.TouchUpInside -= SelectAccessory;
disclosure.TouchUpInside += SelectAccessory;
}
}
...
}
And the change was to this line to look for UIButton now along with UITableViewCellDetailDisclosureView
var disclosure = this.GetSubview<UIControl>(
c => c.Description.StartsWith("<UITableViewCellDetailDisclosureView")
|| c.Description.StartsWith("<UIButton")); // <-- the "fix"
In the MainActivity OnCreate, I set the color of the StatusBar using:
Window.SetStatusBarColor(Resources.GetColor(Resource.Color.colorPrimary));
For the specific pages, I need to set the StatusBar color trasparent.
Is possible to do that in a Android custom rendered class?
EDIT:
my OnLayout method on custom ANdorid
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
CustomNavigation.IgnoreLayoutChange = true;
base.OnLayout(changed, l, t, r, b);
CustomNavigation.IgnoreLayoutChange = false;
int containerHeight = b - t;
PageController.ContainerArea = new Rectangle(0, 0, Context.FromPixels(r - l), Context.FromPixels(containerHeight));
if (Element?.Navigation?.NavigationStack.Count == 1)
{
CustomNavigation.BarBackgroundColor = Color.Transparent;
//HERE I NEED TO HAVE STATUS AR TRANSPARENT
}
if (Element?.Navigation?.NavigationStack.Count > 1)
{
PageController.ContainerArea = new Rectangle(0, 60, Context.FromPixels(r - l), Context.FromPixels(containerHeight));
CustomNavigation.BarBackgroundColor = Color.FromHex("#006CA6");
}
for (var i = 0; i < ChildCount; i++)
{
AView child = GetChildAt(i);
if (child is Android.Support.V7.Widget.Toolbar)
{
continue;
}
child.Layout(0, 0, r, b);
}
}
Status bar appearance is about its background and text colours. Both properties have their own limitations on different platforms, however, we could manipulate both with the solution described below.
Our goal is simple, we want to be able to switch the status bar appearance between LightTheme and DarkTheme at runtime:
Define an interface in your shared code:
public interface IStatusBarStyleManager
{
void SetLightTheme();
void SetDarkTheme();
}
Since Android Lollipop (21) it is possible to set a custom status bar background colour by simply defining it in style.xml with a key colorPrimaryDark or programmatically, Since Android M (23) it is possible to set a predefined status bar text colour theme to light or dark.
Android code:
public class StatusBarStyleManager : IStatusBarStyleManager
{
public void SetDarkTheme()
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
{
Device.BeginInvokeOnMainThread(() =>
{
var currentWindow = GetCurrentWindow();
currentWindow.DecorView.SystemUiVisibility = 0;
currentWindow.SetStatusBarColor(Android.Graphics.Color.DarkCyan);
});
}
}
public void SetLightTheme()
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
{
Device.BeginInvokeOnMainThread(() =>
{
var currentWindow = GetCurrentWindow();
currentWindow.DecorView.SystemUiVisibility = (StatusBarVisibility)SystemUiFlags.LightStatusBar;
currentWindow.SetStatusBarColor(Android.Graphics.Color.LightGreen);
});
}
}
Window GetCurrentWindow()
{
var window = CrossCurrentActivity.Current.Activity.Window;
// clear FLAG_TRANSLUCENT_STATUS flag:
window.ClearFlags(WindowManagerFlags.TranslucentStatus);
// add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
return window;
}
}
I am using the Current Activity Plugin by James Montemagno to get the reference of the current activity.
iOS code:
In iOS the status bar background colour by default matching the colour of the navigation bar. In other words, we don’t have to explicitly set the background colour of the status bar if we want it to match the background colour of the navigation bar. Since iOS 7 it is possible to set a predefined status bar text colour theme to light or dark. However, we will have to manipulate the Info.plist. Since status bar behaviour is determined by view controllers by default, we have to disable this:
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
Next, we can define a default text colour theme:
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleDefault</string>
public class StatusBarStyleManager : IStatusBarStyleManager
{
public void SetDarkTheme()
{
Device.BeginInvokeOnMainThread(() =>
{
UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.LightContent, false);
GetCurrentViewController().SetNeedsStatusBarAppearanceUpdate();
});
}
public void SetLightTheme()
{
Device.BeginInvokeOnMainThread(() =>
{
UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.Default, false);
GetCurrentViewController().SetNeedsStatusBarAppearanceUpdate();
});
}
UIViewController GetCurrentViewController()
{
var window = UIApplication.SharedApplication.KeyWindow;
var vc = window.RootViewController;
while (vc.PresentedViewController != null)
vc = vc.PresentedViewController;
return vc;
}
}
Goodluck
Revert in case of queries.
Im used similar gesture recognizer on Image and it worked. But on a
map nothing work. What could be the reason? Im testing it on Droid project.
public class MapPage : ContentPage
{
Map map;
public MapPage()
{
map = new ExtendedMap
{
IsShowingUser = true,
HeightRequest = 100,
WidthRequest = 940,
VerticalOptions = LayoutOptions.FillAndExpand
};
map.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(()=> { OnAlertYesNoClicked(null, null); }),
NumberOfTapsRequired = 1
});
ContentLayout.Children.Add(map);
}
void NavClicked(object sender, EventArgs e)
{
IsShowRightPanel = !IsShowRightPanel;
}
async void OnAlertYesNoClicked(object sender, EventArgs e)
{
var answer = await DisplayAlert("Question?", "Would you like to play a game", "Yes", "No");
}
}
Not sure why it is not fired, but I can imagine it's not working because the map itself catches tap events etc.
I see you are using the ExtendedMap, have a look at TKCustomMap instead. It has a property for a Command to invoke code when the map is tapped.
Now before anyone ignores this as a duplicate please read till the end. What I want to achieve is this
I've been doing some googling and looking at objective c and swift responses on stackoverflow as well. And this response StackOverFlowPost seemed to point me in the right direction. The author even told me to use ClipsToBounds to clip the subview and ensure it's within the parents bounds. Now here's my problem, if I want to show an image on the right side of the entry(Gender field), I can't because I'm clipping the subview.
For clipping, I'm setting the property IsClippedToBounds="True" in the parent stacklayout for all textboxes.
This is the code I'm using to add the bottom border
Control.BorderStyle = UITextBorderStyle.None;
var myBox = new UIView(new CGRect(0, 40, 1000, 1))
{
BackgroundColor = view.BorderColor.ToUIColor(),
};
Control.AddSubview(myBox);
This is the code I'm using to add an image at the beginning or end of an entry
private void SetImage(ExtendedEntry view)
{
if (!string.IsNullOrEmpty(view.ImageWithin))
{
UIImageView icon = new UIImageView
{
Image = UIImage.FromFile(view.ImageWithin),
Frame = new CGRect(0, -12, view.ImageWidth, view.ImageHeight),
ClipsToBounds = true
};
switch (view.ImagePos)
{
case ImagePosition.Left:
Control.LeftView.AddSubview(icon);
Control.LeftViewMode = UITextFieldViewMode.Always;
break;
case ImagePosition.Right:
Control.RightView.AddSubview(icon);
Control.RightViewMode = UITextFieldViewMode.Always;
break;
}
}
}
After analysing and debugging, I figured out that when OnElementChanged function of the Custom Renderer is called, the control is still not drawn so it doesn't have a size. So I subclassed UITextField like this
public class ExtendedUITextField : UITextField
{
public UIColor BorderColor;
public bool HasBottomBorder;
public override void Draw(CGRect rect)
{
base.Draw(rect);
if (HasBottomBorder)
{
BorderStyle = UITextBorderStyle.None;
var myBox = new UIView(new CGRect(0, 40, Frame.Size.Width, 1))
{
BackgroundColor = BorderColor
};
AddSubview(myBox);
}
}
public void InitInhertedProperties(UITextField baseClassInstance)
{
TextColor = baseClassInstance.TextColor;
}
}
And passed the hasbottomborder and bordercolor parameters like this
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
var view = e.NewElement as ExtendedEntry;
if (view != null && Control != null)
{
if (view.HasBottomBorder)
{
var native = new ExtendedUITextField
{
BorderColor = view.BorderColor.ToUIColor(),
HasBottomBorder = view.HasBottomBorder
};
native.InitInhertedProperties(Control);
SetNativeControl(native);
}
}
But after doing this, now no events fire :(
Can someone please point me in the right direction. I've already built this for Android, but iOS seems to be giving me a problem.
I figured out that when OnElementChanged function of the Custom Renderer is called, the control is still not drawn so it doesn't have a size.
In older versions of Xamarin.Forms and iOS 9, obtaining the control's size within OnElementChanged worked....
You do not need the ExtendedUITextField, to obtain the size of the control, override the Frame in your original renderer:
public override CGRect Frame
{
get
{
return base.Frame;
}
set
{
if (value.Width > 0 && value.Height > 0)
{
// Use the frame size now to update any of your subview/layer sizes, etc...
}
base.Frame = value;
}
}
I am porting my space shooter game from Windows Phone to Windows Store App. In WP it always play in full portrait orientation.
For the Windows Store app though while in landscape mode, I want to center the game screen with letterboxing on the left and right. The problem is I can't adjust the margin property of SwapChainBackgroundPanel so the game always aligned to the left and the black screen is on the right.
Here's my code
public Game1()
{
graphics = new GraphicsDeviceManager(this);
GamePage.Current.SizeChanged += OnWindowSizeChanged;
Content.RootDirectory = "Content";
}
private void OnWindowSizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
{
var CurrentViewState = Windows.UI.ViewManagement.ApplicationView.Value;
double width = e.NewSize.Width;
double height = e.NewSize.Height;
// using Windows.Graphics.Display;
ResolutionScale resolutionScale = DisplayProperties.ResolutionScale;
string orientation = null;
if (ApplicationView.Value == ApplicationViewState.FullScreenLandscape)
{
orientation = "FullScreenLandscape";
//Does not work because it's start on the center of the screen
//Black screen is on the left and place the game screen on the right
GamePage.Current.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center;
//Gives error - WinRT information: Setting 'Margin' property is
//not supported on SwapChainBackgroundPanel.
GamePage.Current.Margin = new Thickness(centerMargin, 0, 0, 0);
}
else if (ApplicationView.Value == ApplicationViewState.FullScreenPortrait)
{
orientation = "FullScreenPortrait";
}
else if (ApplicationView.Value == ApplicationViewState.Filled)
{
orientation = "Filled";
}
else if (ApplicationView.Value == ApplicationViewState.Snapped)
{
orientation = "Snapped";
}
Debug.WriteLine("{0} x {1}. Scale: {2}. Orientation: {3}",
width.ToString(), height.ToString(), resolutionScale.ToString(),
orientation);
}
The GamePage.xaml is the default
<SwapChainBackgroundPanel
x:Class="SpaceShooterXW8.GamePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SpaceShooterXW8"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
</SwapChainBackgroundPanel>
After some researched I think I've figured it out thanks to this blog post. To those who are in a similar situation, here's what I did.
The beauty of the solution is that the letterboxing is automatically managed by the Resolution class. All I have to do is update the batch.begin() lines in my code to something like
batch.Begin(SpriteSortMode.Deferred,
null, SamplerState.LinearClamp,
null,
null,
null,
Resolution.getTransformationMatrix());
To handle resolution changes as the orientation changed I use this in my Game1.cs
public Game1()
{
graphics = new GraphicsDeviceManager(this);
GamePage.Current.SizeChanged += OnWindowSizeChanged;
Content.RootDirectory = "Content";
Resolution.Init(ref graphics);
Resolution.SetVirtualResolution(480, 800);
}
private void OnWindowSizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
{
var CurrentViewState = Windows.UI.ViewManagement.ApplicationView.Value;
App.AppWidth = (int)e.NewSize.Width;
App.AppHeight = (int)e.NewSize.Height;
Resolution.SetResolution(App.AppWidth, App.AppHeight, true);
}
The initial values of App.AppWidth and App.AppHeight is set in the GamePage.xaml.cs.
public GamePage(string launchArguments)
{
this.InitializeComponent();
App.AppWidth = (int)Window.Current.Bounds.Width;
App.AppHeight = (int)Window.Current.Bounds.Height;
Current = this;
// Create the game.
_game = XamlGame<Game1>.Create(launchArguments, Window.Current.CoreWindow, this);
}
Both are global static property created in the App.xaml.cs
public static int AppWidth { get; set; }
public static int AppHeight { get; set; }
The only problem I've encountered so far, the mouse input does not scale to the screen resolution change. I do not have a touch screen to test unfortunately but I think touch input should scale. If anyone tested touch, please share your findings. Thanks.
Update
I've managed to scale the Mouse input using the following
public static Vector2 ScaleGesture(Vector2 position)
{
int x = (int)(position.X / (float)App.AppWidth * (float)Screen.ScreenWidth);
int y = (int)(position.Y / (float)App.AppHeight * (float)Screen.ScreenHeight);
var scaledPosition = new Vector2(x, y);
return scaledPosition;
}