Cancel click on searchbar gives object reference error - xamarin.forms

I created a custom renderer for searchbar to change its UI. The custom renderer is as below. Issue is when I click n cancel button, it gives an object reference error. Can someone tell me what I should do?
[assembly: ExportRendererAttribute(typeof(TransparentSearchBar),typeof(TransparentSearchBarRenderer))]
namespace AmerisureMobile.iOS
{
public class TransparentSearchBarRenderer : SearchBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
UISearchBar bar = this.Control;
bar.BarTintColor = UIColor.FromRGBA(155, 155, 155, 155);
bar.SetSearchFieldBackgroundImage(null, UIControlState.Normal);
bar.AutocorrectionType = UITextAutocorrectionType.No;
bar.TintColor = UIColor.FromRGBA(0, 0, 0, 0);
bar.BackgroundColor = UIColor.FromRGBA(0, 0, 0, 0);
bar.SearchBarStyle = UISearchBarStyle.Minimal;
bar.SetBackgroundImage(new UIImage(), UIBarPosition.TopAttached, UIBarMetrics.Default);
bar.SetImageforSearchBarIcon(new UIImage(), UISearchBarIcon.Clear, UIControlState.Disabled);
UITextField txSearchField = (UITextField)Control.ValueForKey(new Foundation.NSString("searchField"));
txSearchField.BackgroundColor = UIColor.White;
txSearchField.BorderStyle = UITextBorderStyle.None;
txSearchField.Layer.BorderWidth = 1.0f;
txSearchField.Layer.CornerRadius = 2.0f;
txSearchField.Layer.BorderColor = UIColor.LightGray.CGColor;
}
}
}

Try to override the method with click event by adding delegate to searchbar.
//***
bar.Delegate = new MySearchBarDelegate();
class MySearchBarDelegate: UISearchBarDelegate
{
public override void CancelButtonClicked(UISearchBar searchBar)
{
//debug here
}
}

Related

animate page from right to left or left to right?

in my application i am using PushModalAsync and PopModalAsync for page navigation but page animation is displaying from bottom top and top to bottom respectively. Is there any other option to animate page from right to left or left to right?
Welcome to SO!
If using PushModelAsync , there is a workaround to achieve that effect .
Create a CustomPageRenderer for PageTwo in iOS solution :
[assembly: ExportRenderer(typeof(PageTwo), typeof(CustomPageRenderer))]
namespace XamarinMoelNavigationStyle.iOS
{
public class CustomPageRenderer :PageRenderer
{
public override void ViewWillAppear(bool animated)
{
var transition = CATransition.CreateAnimation();
transition.Duration = 0.5f;
transition.Type = CAAnimation.TransitionPush;
transition.Subtype = CAAnimation.TransitionFromRight;
View.Layer.AddAnimation(transition, null);
base.ViewWillAppear(animated);
}
}
}
We will add animation inside ViewWillAppear method .
When poping to previous MainPage , we can deal with that in ContentPage as follow :
private void Button_Clicked(object sender, EventArgs e)
{
PageTwoView.TranslateTo(300, 0, 500);
Device.StartTimer(TimeSpan.FromSeconds(0.5), () =>
{
// Do something
Navigation.PopModalAsync(false);
return false; // True = Repeat again, False = Stop the timer
});
}
Here PageTwoView is defined from Xaml :
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Name="PageTwoView"
x:Class="XamarinMoelNavigationStyle.PageTwo">
...
</ContentPage>
Note : When MainPage navigate to PageTwo , need to disable the animation .
Such as :
private void Button_Clicked(object sender, EventArgs e)
{
Navigation.PushModalAsync(new PageTwo(), false);
}
The effect :
===============================Update #1==============================
Also create a CustomPageRenderer for PageTwo in Android solution :
public class CustomPageRenderer : PageRenderer
{
public CustomPageRenderer(Context context) : base(context)
{
}
protected override void OnAttachedToWindow()
{
var metrics = Resources.DisplayMetrics;
Android.Views.Animations.Animation translateAnimation = new TranslateAnimation(metrics.WidthPixels, 0, 0, 0);
translateAnimation.Duration = 500;
Animation = translateAnimation;
translateAnimation.Start();
base.OnAttachedToWindow();
}
}
The effect:
===============================Update #2=================================
If there are much ContentPages need to navigate, you can modify the CustomPageRenderer to be used for all ContentPage. As follow:
[assembly: ExportRenderer(typeof(ContentPage), typeof(CustomPageRenderer))]
...
Then using Preferences to set flag in Forms and get flag to know whether need the animation.
private void Button_Clicked(object sender, EventArgs e)
{
PageTwo pageTwo = new PageTwo();
// set a flag here
Preferences.Set("ModelAnimation", true);
Navigation.PushModalAsync(pageTwo, false);
}
Now the renderer will know whehter need the animatin:
//Android
protected override void OnAttachedToWindow()
{
var myValue = Preferences.Get("ModelAnimation", false);
if (myValue)
{
var metrics = Resources.DisplayMetrics;
Android.Views.Animations.Animation translateAnimation = new TranslateAnimation(metrics.WidthPixels, 0, 0, 0);
translateAnimation.Duration = 500;
Animation = translateAnimation;
translateAnimation.Start();
}
base.OnAttachedToWindow();
}
//iOS
public override void ViewWillAppear(bool animated)
{
var myValue = Preferences.Get("ModelAnimation", false);
if (myValue)
{
var transition = CATransition.CreateAnimation();
transition.Duration = 0.5f;
transition.Type = CAAnimation.TransitionPush;
transition.Subtype = CAAnimation.TransitionFromRight;
View.Layer.AddAnimation(transition, null);
}
base.ViewWillAppear(animated);
}
after sliding complete 1st page is open as popup and not looking like first page to second page animation..
About this issue, you can share some code and .gif to explain that.

How to create scrollview with fading edges in Xamarin forms? (Xamarin.ios)

I already have a custom renderer for scrollview that will create fading edges on Xamarin.android. So my problem now is that my renderer on iOS is not working.
Here is what I have:
using System;
using CoreAnimation;
using CoreGraphics;
using Foundation;
using Omregistrering.CustomControls;
using Omregistrering.iOS.Renderers;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(FadeScrollView), typeof(FadeScrollViewRenderer))]
namespace Omregistrering.iOS.Renderers
{
public class FadeScrollViewRenderer : ScrollViewRenderer
{
private CAGradientLayer gradientLayer;
private Double FadePercentage = 0.2;
private CGColor OpaqueColor = UIColor.Black.CGColor;
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
//UpdateScrollView();
}
public override void ScrollRectToVisible(CGRect rect, bool animated)
{
base.ScrollRectToVisible(rect, animated);
}
private void UpdateScrollView()
{
// test with Bounces
ContentInset = new UIKit.UIEdgeInsets(0, 0, 0, 0);
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
ContentInsetAdjustmentBehavior = UIKit.UIScrollViewContentInsetAdjustmentBehavior.Never;
Bounces = false;
ScrollIndicatorInsets = new UIKit.UIEdgeInsets(0, 0, 0, 0);
}
private CGColor topOpacity()
{
var scrollViewHeight = Frame.Size.Height;
var scrollContentSizeHeight = ContentSize.Height;
var scrollOffset = ContentOffset.Y;
nfloat alpha = (scrollViewHeight >= scrollContentSizeHeight || scrollOffset <= 0) ? 1 : 0;
var color = new UIColor(white: 0, alpha: alpha);
return color.CGColor;
}
private CGColor bottomOpacity()
{
var scrollViewHeight = Frame.Size.Height;
var scrollContentSizeHeight = ContentSize.Height;
var scrollOffset = ContentOffset.Y;
nfloat alpha = (scrollViewHeight >= scrollContentSizeHeight || scrollOffset + scrollViewHeight >= scrollContentSizeHeight) ? 1 : 0;
var color = new UIColor(white: 0, alpha: alpha);
return color.CGColor;
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
gradientLayer = new CAGradientLayer();
gradientLayer.Frame = rect;
var maskLayer = new CALayer();
gradientLayer.Colors = new CGColor[] { topOpacity(), OpaqueColor, OpaqueColor, bottomOpacity() };
gradientLayer.Locations = new NSNumber[] { 0, (NSNumber)FadePercentage, (NSNumber)(1 - FadePercentage), 1 };
maskLayer.AddSublayer(gradientLayer);
this.Layer.Mask = maskLayer;
}
}
}
And the result is this:
The renderer is fading at the bottom edge but is not updated in any way.The ideer is of course to have fading edges also when scrolling up and down.
Here a screenshot from android were we are in the middle of a scroll and both edges are fading, giving the illusion of more content.
Anyone who have a solution or has done this on Xamarin.ios
Thanks
I don't think you need renderers here.
You could use two png with gradient toward transparent, for each edge.
Then with ScrollView.Scrolled event, you can know if you reached the top or the bottom of the scroll view.
Doing so, you can set the opacity of the 2 images according to the distance from the edge.
In the following example, we'll consider only bottom:
private void OnScrolled(object sender, ScrolledEventArgs e)
{
MyScrollView scrollView = sender as MyScrollView;
double scrollingSpace = scrollView.ContentSize.Height - scrollView.Height;
MyBottomImage.Opacity = 1 - e.ScrollY/scrollingSpace;
}
I hope you get the idea :)

How to remove the bottom line of datepicker in android using xamarin.forms

I'm using DatePicker control in my xamarin.forms application which shows a bottom line for date picker in android devices but idon't want that line. How can I remove that line??
I've try to remove the line by using some custom renders but it doesn't work. The renderer I've tried to apply is:
public class BorderlessDatePickerRenderer:DatePickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
Control.Background = null;
var layoutParams = new MarginLayoutParams(Control.LayoutParameters);
layoutParams.SetMargins(0, 0, 0, 0);
LayoutParameters = layoutParams;
Control.LayoutParameters = layoutParams;
Control.SetPadding(0, 0, 0, 0);
SetPadding(0, 0, 0, 0);
}
}
}
Can someone please help me with this.
Thank you.
You can set the background to empty and it should work:
Control.SetBackgroundResource(0);
Update:
[assembly: ExportRenderer(typeof(BorderlessDatePicker), typeof(BorderlessDatePickerRenderer))]
public class BorderlessDatePickerRenderer : DatePickerRenderer
{
public static void Init() { }
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
Control.Background = null;
var layoutParams = new MarginLayoutParams(Control.LayoutParameters);
layoutParams.SetMargins(0, 0, 0, 0);
LayoutParameters = layoutParams;
GradientDrawable gd = new GradientDrawable();
gd.SetStroke(0, Android.Graphics.Color.LightGray);
Control.SetBackgroundDrawable(gd);
Control.LayoutParameters = layoutParams;
Control.SetPadding(0, 0, 0, 0);
SetPadding(0, 0, 0, 0);
}
}
}
In case of queries feel free to revert
You can use a transparent gradiant into OnElementChanged
var gd = new GradientDrawable();
gd.SetStroke(0, Android.Graphics.Color.Transparent);
Control.SetBackground(gd);

Add bottom line in android custom renderer code?

I know the default DatePicker already has a bottom line, but I'm trying to add a bottom line to the DatePicker in the custom renderer code (for some purpose).
I can set a full border of my GradientDrawable object by myGradientDrawable.SetStroke(3, myColor); but I don't know how to add only the bottom line so anyone can help me please?
Try this:
public class CustomPickerRenderer : PickerRenderer
{
public CustomPickerRenderer(Context context) : base(context)
{
}
private AlertDialog alert;
private CustomPicker element;
private int selectedIndex;
public LayerDrawable AddPickerStyles(string imagePath)
{
ColorDrawable borderColorDrawable = new ColorDrawable(Xamarin.Forms.Color.FromHex("#43addf").ToAndroid());
ColorDrawable backgroundColorDrawable = new ColorDrawable(Xamarin.Forms.Color.FromHex("#7e1b80").ToAndroid());
Drawable[] drawables = new Drawable[]
{
borderColorDrawable, backgroundColorDrawable
};
LayerDrawable layerDrawable = new LayerDrawable(drawables);
layerDrawable.SetLayerInset(1, 0, 0, 0, 5);
return layerDrawable;
}
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
element = (CustomPicker)this.Element;
if (Control != null && this.Element != null)
{
Control.Background = AddPickerStyles(element.Image);
}
}
}

Entry render not adding underline in iOS Xamarin Forms

I have an Entry in Xamarin Forms and for Android, its displayed with an underline by default and when I test it for iOS it's always with a rectangle like this:
And I want it to be like just like in Android:
I used Custom render where I specified that I want an underline but its still displayed in a rectangle. This code doesn't work:
class MyEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.BorderStyle = UITextBorderStyle.Line;
}
}
}
I have solved this problem with the next code:
class MyEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.BorderStyle = UITextBorderStyle.None;
//Create borders(bottom only)
CALayer border = new CALayer();
float width = 2.0f;
border.BorderColor = Color.FromHex(ColorConstants.BlueHex).ToCGColor();
border.Frame = new CGRect( 0, 40, 400, 2.0f);
border.BorderWidth = width;
Control.Layer.AddSublayer(border);
Control.Layer.MasksToBounds = true;
}
}
}
But still, don't understand why the previous code doesn't work, it should be simple as that. Any ideas?
https://developer.xamarin.com/api/type/UIKit.UITextBorderStyle/
The enum values for UITextBorderStyle are Bezel, Line, None, and RoundedRect. All of them (except for None) simply describe the style of the border that goes around the entire UITextView, so the Line value doesn't mean a single line, it means a solid line rectangle around the entire view, as opposed to a Bezel or rounded rectangle.
the implementation witch has solved the user question didn't work for me in these days, but this one has worked: https://social.msdn.microsoft.com/Forums/en-US/7ae2e5ad-3cc4-4761-ac39-06e8d8842cf4/entry-bottom-line?forum=xamarinforms
as jmoerdyk gently suggested this link explains how to write a custom renderer for iOS to render an entry with a bottom line instead of a complete border. the color of the line will change when the entry has focus.
below the piece of code with some null checks:
public class IOSBottomLineEntryRenderer : EntryRenderer
{
private CALayer _borderLayer;
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control == null)
return;
Control.BorderStyle = UITextBorderStyle.None;
if (Element == null)
return;
DrawBorder(UIColor.FromRGB(156, 156, 156));
e.NewElement.Unfocused += (_, _) =>
{
DrawBorder(UIColor.FromRGB(156, 156, 156));
};
e.NewElement.Focused += (_, _) =>
{
DrawBorder(UIColor.FromRGB(245, 0, 47));
};
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Control == null)
return;
if (Element == null)
return;
DrawBorder(UIColor.FromRGB(156, 156, 156));
}
public override CGRect Frame
{
get { return base.Frame; }
set
{
base.Frame = value;
if (Control == null)
return;
if (Element == null)
return;
DrawBorder(UIColor.FromRGB(156, 156, 156));
}
}
private void DrawBorder(UIColor borderColor)
{
if (Frame.Height <= 0 || Frame.Width <= 0)
return;
if (_borderLayer == null)
{
_borderLayer = new CALayer
{
MasksToBounds = true,
Frame = new CGRect(0f, Frame.Height - 1, Frame.Width, 1f),
BorderColor = borderColor.CGColor,
BorderWidth = 1.0f
};
Control.Layer.AddSublayer(_borderLayer);
Control.BorderStyle = UITextBorderStyle.None;
}
else
{
_borderLayer.BorderColor = borderColor.CGColor;
_borderLayer.Frame = new CGRect(0f, Frame.Height - 1, Frame.Width, 1f);
}
}
}

Resources