ScrollChange event equivalent on iOS - c#

I want to hide a button when the user is scrolling through the page so a specific area of the page is not blocked by the button, after the user finish scrolling I will show the button again after a delay of 1000-1500ms. My idea so far is that I will subscribe to the scroll changing event, hide the button, wait for specific delay, show the button again. I managed to implement it for Android platform using effect like this:
public class AndroidScrollingEffect : Xamarin.Forms.Platform.Android.PlatformEffect
{
private bool _isAttached;
public static void Initialize() { }
protected override void OnAttached()
{
if (!_isAttached)
{
Control.ScrollChange += Control_ScrollChange;
_isAttached = true;
}
}
private void Control_ScrollChange(object sender, global::Android.Views.View.ScrollChangeEventArgs e)
{
var command = ScrollingEffect.GetCommand(Element);
command?.Execute(null);
}
protected override void OnDetached()
{
if (_isAttached)
{
Control.ScrollChange -= Control_ScrollChange;
_isAttached = false;
}
}
}
The implementation is working just fine, for android platform. Now, I want to do the same thing for iOS. So, is there an equivalent event for ScrollChange on iOS?
P.S. I want to use effect so I don't write code in the code behind of the page and still able to bind to a specific command in the view model.

Forms ScrollView is rendered as UIScrollView on iOS. So you can try the code below to construct your custom effect:
public class iOSScrollingEffect : PlatformEffect
{
UIScrollView nativeControl;
private bool _isAttached;
protected override void OnAttached()
{
nativeControl = Control as UIScrollView;
if (nativeControl != null && !_isAttached)
{
nativeControl.Scrolled += NativeControl_Scrolled;
_isAttached = true;
}
}
private void NativeControl_Scrolled(object sender, EventArgs e)
{
...
}
protected override void OnDetached()
{
if (_isAttached)
{
nativeControl.Scrolled -= NativeControl_Scrolled;
_isAttached = false;
}
}
}

Related

Xamarin IOS hide the search bar icon based on IsFocused property in custom renderer

I wanted to hide the search bar icon in IOS using custom SearchBarRenderer based on the IsFocused property. How can I achieve this?
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Element == null || Control == null)
return;
var element = Element as CustomSearchBar;
if (element.IsFocused)
{
}
else
{
}
}
If you are using Custom Renderer to realize it , code as follow .
[assembly: ExportRenderer(typeof(CustomSearchBar), typeof(CustomSearchBarRenderer))]
namespace App15.iOS
{
public class CustomSearchBarRenderer : SearchBarRenderer
{
UIImage searchImg;
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
searchImg = Control.GetImageForSearchBarIcon(UISearchBarIcon.Search, UIControlState.Normal);
if (e.OldElement != null)
{
Control.OnEditingStarted -= Control_OnEditingStarted;
Control.OnEditingStopped -= Control_OnEditingStopped;
}
if (e.NewElement != null)
{
if (null != Control)
{
Control.OnEditingStarted += Control_OnEditingStarted;
Control.OnEditingStopped += Control_OnEditingStopped;
}
}
}
private void Control_OnEditingStopped(object sender, EventArgs e)
{
var searchBar = sender as UISearchBar;
searchBar.SetImageforSearchBarIcon(searchImg, UISearchBarIcon.Search, UIControlState.Normal);
}
private void Control_OnEditingStarted(object sender, EventArgs e)
{
var searchBar = sender as UISearchBar;
searchBar.SetImageforSearchBarIcon(new UIImage(), UISearchBarIcon.Search, UIControlState.Normal);
}
}
}
Note: App15 is namespace in my local project.
As document Introduction to Effects of effects said , you also can refer to this document Creating an Effect to use Effect to realize it ,because it no need to use Custom Renderer to do that .
Sample of Effects as follow:
Creating SearchBarEffects :
public class SearchBarEffects : RoutingEffect
{
public SearchBarEffects() : base($"MyCompany.{nameof(SearchBarEffects)}")
{
}
}
Using in Xaml :
// here is custom renderer
<local:CustomSearchBar Placeholder="renderer input"/>
// here is custom effect
<SearchBar Placeholder="effect input">
<SearchBar.Effects>
<local:SearchBarEffects />
</SearchBar.Effects>
</SearchBar>
Creating SearchBarEffect in iOS solution :
[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(App15.iOS.SearchBarEffect), "SearchBarEffects")]
namespace App15.iOS
{
public class SearchBarEffect : PlatformEffect
{
UIImage searchImg;
protected override void OnAttached()
{
searchImg = ((UISearchBar)Control).GetImageForSearchBarIcon(UISearchBarIcon.Search, UIControlState.Normal);
((UISearchBar)Control).OnEditingStarted += SearchBar_OnEditingStarted;
((UISearchBar)Control).OnEditingStopped += SearchBar_OnEditingStopped;
}
private void SearchBar_OnEditingStopped(object sender, EventArgs e)
{
var searchBar = sender as UISearchBar;
searchBar.SetImageforSearchBarIcon(searchImg, UISearchBarIcon.Search, UIControlState.Normal);
}
private void SearchBar_OnEditingStarted(object sender, EventArgs e)
{
var searchBar = sender as UISearchBar;
searchBar.SetImageforSearchBarIcon(new UIImage(), UISearchBarIcon.Search, UIControlState.Normal);
}
protected override void OnDetached()
{
((UISearchBar)Control).OnEditingStarted -= SearchBar_OnEditingStarted;
((UISearchBar)Control).OnEditingStopped -= SearchBar_OnEditingStopped;
}
}
}
Finally ,showing the effect by two ways . Up is Effect's , down is Renderer's .
Personal note - there is no need to use a Custom Renderer for this, an effect is more than enough - I tested with Effect, not with custom renderer. On how to create Effects, see here
this.Control will be a UISearchBar if you only add this effect to <SearchBar> elements.
So you can do this (based on iOS and Xamarin.iOS documentation):
iOS implementation of effect:
public class NoSearchIconEffect : PlatformEffect
{
UIImage defaultIcon = null;
protected override void OnAttached()
{
var searchBar = this.Control as UISearchBar;
defaultIcon = defaultIcon ?? searchBar.GetImageForSearchBarIcon(UISearchBarIcon.Search, UIControlState.Normal); //This will save the default icon
searchBar.OnEditingStarted += delegate
{
searchBar.SetImageforSearchBarIcon(new UIImage(), UISearchBarIcon.Search, UIControlState.Normal);
};
searchBar.OnEditingStopped += delegate
{
searchBar.SetImageforSearchBarIcon(defaultIcon, UISearchBarIcon.Search, UIControlState.Normal);
};
}
protected override void OnDetached()
{
}
}

OnAppearing Method on IOS

When my app is in the background and goes to foreground, the OnAppearing() method doesnt work in IOS or when the phone is locked and then unlocked and the app is in the foreground the method OnAppearing() isnt called, on Android everything works fine.
I found this guide below, but still doesnt work, i have the last version of xamarin forms.
Guide:
https://kent-boogaart.com/blog/hacking-xamarin.forms-page.appearing-for-ios
Can anyone help me?
As you have seen, the "lifecycles" within iOS are different. One way that helps is to use the Application lifecycles and tie those into Page events (or Commands if needed).
In your Application subclass add a couple of public EventHandlers and tie those into the OnResume (and OnSleep if needed)
public partial class App : Application
{
public EventHandler OnResumeHandler;
public EventHandler OnSleepHandler;
public App()
{
InitializeComponent();
MainPage = new MyPage();
}
protected override void OnSleep()
{
OnSleepHandler?.Invoke(null, new EventArgs());
}
protected override void OnResume()
{
OnResumeHandler?.Invoke(null, new EventArgs());
}
}
Now in your ContentPage subclass, add a handler that tracks when that page comes back from being in the background, kind-of an "OnAppearing after OnPause" handler...
void Handle_OnResumeHandler(object sender, EventArgs e)
{
Console.WriteLine("OnPauseResumeWithPage");
}
protected override void OnAppearing()
{
(App.Current as App).OnResumeHandler += Handle_OnResumeHandler;
base.OnAppearing();
}
protected override void OnDisappearing()
{
(App.Current as App).OnResumeHandler -= Handle_OnResumeHandler;
base.OnDisappearing();
}

How to use the back function in UWP apps to change visibility of a grid?

I would like to use the back function in the UWP in the App.xaml.cs file to change the visibility property of a grid (grid1) on the MainPage.xaml file.
//Go Back
public void App_BackRequested(object sender, Windows.UI.Core.BackRequestedEventArgs e)
{
if(MainPage.MyGlobals.pageLocation == 0)
{
//Do Nothing
}
else if(MainPage.MyGlobals.pageLocation == 1)
{
MainPage.grid1.Visibility = Visibility.Collapsed;
MainPage.MyGlobals.pageLocation = 0;
}
}
I know it's not typical practice to change xaml elements' properties from a different page, but I would really like to change how the back feature works in this app. I believe I have to make the grid pubic, but even when I (thought I) found a way to do that I still couldn't change the properties of the grid with the way I have it written in my code.
As you've mentioned, changing XAML elements' properties from a different page is not a good practice. We can just use SystemNavigationManager.BackRequested event in MainPage like following to change the visibility of a grid.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
SystemNavigationManager.GetForCurrentView().BackRequested += Page_BackRequested;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
SystemNavigationManager.GetForCurrentView().BackRequested -= Page_BackRequested;
}
private void Page_BackRequested(object sender, BackRequestedEventArgs e)
{
if (MyGrid.Visibility == Visibility.Visible)
{
MyGrid.Visibility = Visibility.Collapsed;
e.Handled = true;
}
else
{
if (this.Frame.CanGoBack)
{
this.Frame.GoBack();
e.Handled = true;
}
}
}
And if you want to take advantage of the back function in App.xaml.cs and use a different function in MainPage, you can add a event in App that wraps SystemNavigationManager.BackRequested to allow other pages to override the default behavior by subscribing to this event like following:
public event EventHandler<BackRequestedEventArgs> BackRequested;
private void App_BackRequested(object sender, BackRequestedEventArgs e)
{
BackRequested?.Invoke(sender, e);
Frame rootFrame = Window.Current.Content as Frame;
if (!e.Handled && rootFrame != null && rootFrame.CanGoBack)
{
rootFrame.GoBack();
e.Handled = true;
}
}
Then in MainPage, subscribe and unsubscribe this event like:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
(Application.Current as App).BackRequested += Page_BackRequested;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
(Application.Current as App).BackRequested -= Page_BackRequested;
}
It doesn't work because you're trying to access the Grid as if it was a static property of the MainPage. You need a reference to the MainPage instance to manipulate the Grid, but all in all it is a really bad practice. You should have a look at the UWP/WP 8.1 navigation events.

Xamarin iOS UIButton How To Click button programmatically?

I'm attempting to fake the act of clicking a button, by programmatically calling it within my ViewWillAppear() function.
The onclick function is defined in my ViewDidLoad(), and you can see I am trying to use a Perform Selector to manually call the button.
The button does not appear to be running. Any ideas?
public override void ViewDidLoad()
{
base.ViewDidLoad();
idButtonScanLoad.TouchUpInside += async (sender, ea) =>
{
System.Console.WriteLine("Scan button pressed");
};
}
[Export("TouchUpInsideEvent:")]
private void TouchUpInsideEvent(NSObject sender)
{
Console.WriteLine("yay!");
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
this.PerformSelector(new ObjCRuntime.Selector("TouchUpInsideEvent:"), this as NSObject, 10f);
}
Here is the answer, you should call it from your ViewDidLoad method.
myButton.SendActionForControlEvents (UIControlEvent.TouchUpInside);
If you want to create a button's click event, you can use the this
public override void ViewDidLoad()
{
Mybutton.AddTarget(ButtonEventHandler, UIControlEvent.TouchUpInside);
}
public void ButtonEventHandler(object sender, EventArgs e)
{
if(sender==Mybutton)
{
//do stuff here
}
}

Add semi-transparent button to ListView

I have listview control. I need to add semi-transparent button with image to listview. Something like this:
I found several projects that use semi-transparent buttons on the form. But when I transfer them to the ListView, they do not work.
Necessary to use .net 2.0 framework.
I found some solution.
Making Transparent Controls - No Flickering
I inherit my TransparentToggleButton class from TranspControl class:
public class TransparentToggleButton : TranspControl
{
private Image _normalState;
private Image _mouseUpState;
private Image _activateState;
private bool _state;
private bool _mouseUnder;
public event EventHandler StateChanged;
public bool ToggleState
{
get { return _state; }
set
{
_state = value;
SetImage();
}
}
public void SetImages(Image normalState, Image mouseUpState, Image activateState)
{
BackImage = normalState;
_normalState = normalState;
_mouseUpState = mouseUpState;
_activateState = activateState;
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
if (e.Button == MouseButtons.Left)
{
_state = !_state;
if (StateChanged != null)
StateChanged(this, e);
SetImage();
}
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
_mouseUnder = true;
SetImage();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
_mouseUnder = false;
SetImage();
}
private void SetImage()
{
try
{
if (_state)
BackImage = _activateState;
else
BackImage = _mouseUnder ? _mouseUpState : _normalState;
}
catch (Exception)
{
}
}
}
Function SetImages loads the 3 images that used for normal state, normal state when cursor over the button, activate state.
Besides need catch listview scroll event and Invalidate() TransparentToggleButton.

Categories

Resources