Custom renderer for Android CardView not showing Forms component content - xamarin

I've created a custom component which extends ContentView and renderer which renders to a CardView on Android.
The problem I am facing is that the Forms content is rendered below the CardView. On KitKat this does not occur, but I think the CardView implementation is not the same as on Lollipop or newer.
Setting the background color of the CardView to transparent (0x00000000) reveals the content below the CardView.
The forms component:
using Xamarin.Forms;
namespace CodeFest
{
public class NativeClientProfile : ContentView
{
public NativeClientProfile()
{
var grid = new Grid
{
RowDefinitions = new RowDefinitionCollection {new RowDefinition()},
ColumnDefinitions = new ColumnDefinitionCollection {new ColumnDefinition(), new ColumnDefinition()}
};
grid.Children.Add(new Label {Text = "FSP No"}, 0, 0);
grid.Children.Add(new Label {Text = "12345", HorizontalTextAlignment = TextAlignment.Center}, 1, 0);
grid.Children.Add(new Label {Text = "Risk"}, 0, 1);
grid.Children.Add(
new Label {Text = "Low", TextColor = Color.Green, HorizontalTextAlignment = TextAlignment.Center}, 1, 1);
var item = new Label
{
Text = "Foo bar",
HorizontalTextAlignment = TextAlignment.Center,
FontSize = 30,
FontAttributes = FontAttributes.Bold
};
Content = new StackLayout
{
Children =
{
item,
new Label
{
Text = "Financial Services Provider",
HorizontalTextAlignment = TextAlignment.Center
},
grid
}
};
}
}
}
The custom renderer:
using Android.Support.V7.Widget;
using Android.Text;
using Android.Views;
using CodeFest;
using CodeFest.Droid.ComponentRenderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(NativeClientProfile), typeof(NativeClientProfileRenderer))]
namespace CodeFest.Droid.ComponentRenderers
{
class NativeClientProfileRenderer : ViewRenderer<NativeClientProfile, CardView>
{
protected override void OnElementChanged(ElementChangedEventArgs<NativeClientProfile> elementChangedEventArgs)
{
var view = new CardView(Context);
//view.SetCardBackgroundColor(0x00000000);
SetNativeControl(view);
}
}
}
I am looking for an example of how to correctly render forms components within a CardView custom renderer.

You can use a Frame as base class instead of ContentView. This has the advantage, that you can use the existing FrameRenderer of Xamarin.Forms.Platform.Android.AppCompat which is already using a CardView. (see: FrameRenderer.cs).
FrameRenderer declaration
public class FrameRenderer : CardView, IVisualElementRenderer, AView.IOnClickListener, AView.IOnTouchListener
Renderer
class NativeClientProfileRenderer : Xamarin.Forms.Platform.Android.AppCompat.FrameRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
{
base.OnElementChanged(e);
}
}
NativeClientProfile
public class NativeClientProfile : Frame
{
public NativeClientProfile()
{
// your stuff...
Content = new StackLayout
{
Children =
{
item,
new Label
{
Text = "Financial Services Provider",
HorizontalTextAlignment = TextAlignment.Center
},
grid
}
};
}
}
Discussion
The renderer shows you what it needs if you really want to do it manually. Using the FrameRenderer makes your code dependent on the implementation of Xamarin. If they ever change the type of view that is rendered for a Frame it will break your App. But if you have a look at the implementation of the FrameRenderer, I'd try to avoid creating it completely from scratch (simple risk vs. effort evaluation).

Related

Detect Phone Number & Link in xamarin.Form

assume we have the following text :
Contact us on 015546889 or email#hotmail.com
How I can display the above text in same label in xamarin.forms and handle click on email by send email and handle phone call by click on the number.
I can use the the following code to make clickable label
Label label = new Label;
label.GestureRecognizers.Add(new TapGestureRecognizer()
{
Command = new Command(() => {
//do some function here
})
});
How to hyperlink same as messaging app or Whatsapp application
After a lot of search i found the perfect solution Here :
https://theconfuzedsourcecode.wordpress.com/tag/xamarin-hyperlink-label/
Hope this will help others :)
Check out the Label element in Forms9Patch. It has a HtmlText property that allows simple markup.
using System;
using Xamarin.Forms;
namespace Forms9PatchDemo
{
public class LabelLink : ContentPage
{
public LabelLink()
{
var label = new Forms9Patch.Label
{
HtmlText = "Contact us on <a id=\"phone\" href=\"tel:+353015546889\">015546889</a> or <a id=\"email\" href=\"mailto:email#hotmail.com\">email#hotmail.com</a>"
};
label.ActionTagTapped += (object sender, Forms9Patch.ActionTagEventArgs e) =>
{
var id = e.Id;
var href = e.Href;
var uri = new Uri(e.Href);
Device.OpenUri(uri);
};
Content = new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Children = {
new Label { Text = "Forms9Patch.Label.HtmlText <a> example" },
new BoxView { BackgroundColor = Color.Black, HeightRequest = 1 },
label
}
};
}
}
}
Note that the above example won't work on iOS emulators because the tel: and mailto: schemes are not supported. It does work on actual iOS devices.

Cannot implicily convert type to 'Xamarin.Forms.Page'

I have a Xamarin Forms project, I have updated Xamarin and this is the new App.cs
public App()
{
// The root page of your application
var content = new ContentPage
{
Title = "Proje1",
Content = new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Children = {
new Label {
HorizontalTextAlignment = TextAlignment.Center,
Text = "Welcome to Xamarin Forms!"
}
}
}
};
MainPage = new NavigationPage(content);
}
I get this error
Cannot implicily convert type 'Proje1.Views.View1' to 'Xamarin.Forms.Page'
when I make this
MainPage = new View1();
I was pointing like this before, now how should I set the initial page in App.cs?
I assume View1 inherit from ContentView somehow, so what you need is embed that in a Page so it's fit to be used as Application.MainPage.
MainPage = new ContentPage {
Content = new View1()
};

Xamarin forms tabbed paged swipe invoke event

I am using Xamarin forms to create a TabbedPage. The problem is that I want to swipe between tabs and this is disable by default. I found one class called ExtendedTabbedPage which has one attribute called SwipeEnable and some methods that invoke the swipe event.
This is my class that extends from ExtendedTabbedPage and creates two tabs with some content. I set the value of swipeEnabled attribute but it does not do anything. Is there anyway to invoke the swipe event from this class?
public class TabbedPageComplete: ExtendedTabbedPage
{
public TabbedPageComplete ()
{
this.Title = "TabbedPage";
this.SwipeEnabled = true;
this.Children.Add (new ContentPage
{
Title = "Blue",
Content = new BoxView
{
Color = Color.Blue,
HeightRequest = 100f,
VerticalOptions = LayoutOptions.Center
},
}
);
this.Children.Add (new ContentPage {
Title = "Blue and Red",
Content = new StackLayout {
Children = {
new BoxView { Color = Color.Blue },
new BoxView { Color = Color.Red}
}
}
});
}
}
Did you tested with iOS also or just with Android ?
The ExtendedTabbedPage is currently only implemented for iOS ExtendedTabbedPageRenderer.cs while for Android is still under development.

Background image with Carousel effect

I would like to create a layout with a fullscreen background image and some UI elements on top of it. The twist is this:
I would like the background image to swipeable like a carousel, but I would like the UI elements to stay in place. That is if I swipe the screen, the background image should slide to the side and a new image should replace it. I know about CarouselPage, but it seems to me that it won't do the trick, since a Page can have only one child which it replaces on swipe, meaning that the UI elements would be descendants of the CarouselPage and therefore would also be animated.
I am guessing I need some sort of custom renderer here, but how should I go about designing it? Should it be one fullscreen Image control replaced be another fullscreen Image control with the UI elements on top of it? And how can I do this? Or is there an all together better approach?
I am developing for iOS and Android using Xamarin.Forms.
Thanks in advance.
I don't like repeating myself much, and I think that multiple layers of actionable items can lead to confusion, but the problems appeals to me and I can see a niche for this kind of UI, so here's my take on your question.
Let's assume this is the (Xamarin.Forms.)Page you want to render with a custom carousel background:
public class FunkyPage : ContentPage
{
public IList<string> ImagePaths { get; set; }
public FunkyPage ()
{
Content = new StackLayout {
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center,
Spacing = 12,
Children = {
new Label { Text = "Foo" },
new Label { Text = "Bar" },
new Label { Text = "Baz" },
new Label { Text = "Qux" },
}
};
ImagePaths = new List<string> { "red.png", "green.png", "blue.png", "orange.png" };
}
}
The renderer for iOS could look like this:
[assembly: ExportRenderer (typeof (FunkyPage), typeof (FunkyPageRenderer))]
public class FunkyPageRenderer : PageRenderer
{
UIScrollView bgCarousel = new UIScrollView (RectangleF.Empty) {
PagingEnabled = true,
ScrollEnabled=true
};
List<UIImageView> uiimages = new List<UIImageView> ();
protected override void OnElementChanged (VisualElementChangedEventArgs e)
{
foreach (var sub in uiimages)
sub.RemoveFromSuperview ();
uiimages.Clear ();
if (e.NewElement != null) {
var page = e.NewElement as FunkyPage;
foreach (var image in page.ImagePaths) {
var uiimage = new UIImageView (new UIImage (image));
bgCarousel.Add (uiimage);
uiimages.Add (uiimage);
}
}
base.OnElementChanged (e);
}
public override void ViewDidLoad ()
{
Add (bgCarousel);
base.ViewDidLoad ();
}
public override void ViewWillLayoutSubviews ()
{
base.ViewWillLayoutSubviews ();
bgCarousel.Frame = View.Frame;
var origin = 0f;
foreach (var image in uiimages) {
image.Frame = new RectangleF (origin, 0, View.Frame.Width, View.Frame.Height);
origin += View.Frame.Width;
}
bgCarousel.ContentSize = new SizeF (origin, View.Frame.Height);
}
}
This was tested and works. Adding a UIPageControl (the dots) is easy on top of this. Autoscrolling of the background is trivial too.
The process is similar on Android, the overrides are a bit different.

How can I create a drawer / slider menu with Xamarin.Forms?

How do I create an a slider menu using Xamarin.Forms? Is it baked in or something custom?
You create a new class which contains all the definitions for both the Master - i.e. the menu - and the Detail - i.e. the main page. I know, it sounds back-to-front, but for example..
using System;
using Xamarin.Forms;
namespace testXamForms
{
public class HomePage : MasterDetailPage
{
public HomePage()
{
// Set up the Master, i.e. the Menu
Label header = new Label
{
Text = "MENU",
Font = Font.BoldSystemFontOfSize(20),
HorizontalOptions = LayoutOptions.Center
};
// create an array of the Page names
string[] myPageNames = {
“Main”,
“Page 2”,
“Page 3”,
};
// Create ListView for the Master page.
ListView listView = new ListView
{
ItemsSource = myPageNames,
};
// The Master page is actually the Menu page for us
this.Master = new ContentPage
{
Title = "The Title is required.",
Content = new StackLayout
{
Children =
{
header,
listView
},
}
};
// Define a selected handler for the ListView contained in the Master (ie Menu) Page.
listView.ItemSelected += (sender, args) =>
{
// Set the BindingContext of the detail page.
this.Detail.BindingContext = args.SelectedItem;
Console.WriteLine("The args.SelectedItem is
{0}",args.SelectedItem);
// This is where you would put your “go to one of the selected pages”
// Show the detail page.
this.IsPresented = false;
};
// Set up the Detail, i.e the Home or Main page.
Label myHomeHeader = new Label
{
Text = "Home Page",
HorizontalOptions = LayoutOptions.Center
};
string[] homePageItems = { “Alpha”, “Beta”, “Gamma” };
ListView myHomeView = new ListView {
ItemsSource = homePageItems,
};
var myHomePage = new ContentPage();
myHomePage.Content = new StackLayout
{
Children =
{
myHomeHeader,
myHomeView
} ,
};
this.Detail = myHomePage;
}
}
}
It is built in: MasterDetailPage. You'd set the Detail and Master properties of it to whatever kinds of Pages you'd like. I found Hansleman.Forms to be quite enlightening.
My minimum example (as posted here) is as follows:
public class App
{
static MasterDetailPage MDPage;
public static Page GetMainPage()
{
return MDPage = new MasterDetailPage {
Master = new ContentPage {
Title = "Master",
BackgroundColor = Color.Silver,
Icon = Device.OS == TargetPlatform.iOS ? "menu.png" : null,
Content = new StackLayout {
Padding = new Thickness(5, 50),
Children = { Link("A"), Link("B"), Link("C") }
},
},
Detail = new NavigationPage(new ContentPage {
Title = "A",
Content = new Label { Text = "A" }
}),
};
}
static Button Link(string name)
{
var button = new Button {
Text = name,
BackgroundColor = Color.FromRgb(0.9, 0.9, 0.9)
};
button.Clicked += delegate {
MDPage.Detail = new NavigationPage(new ContentPage {
Title = name,
Content = new Label { Text = name }
});
MDPage.IsPresented = false;
};
return button;
}
}
An example solution is hosted on GitHub.
On iOS the result looks like this (left: menu open, right: after clicking on "B"):
Note that you need to add the menu icon as a resource in your iOS project.
If you are looking for simple example of MasterDetailPage please have a look at my sample repo at GitHub. Very nice example is also presented here
Slideoverkit is a great plugin available for Xamarin Forms. There is a github to see free samples and you could find documentation about it here.

Resources