I used CarouselViewControl (https://github.com/alexrainman/CarouselView) in Xamarin.Forms with My Custom-View. My custom-view
was extended Contentview and was added Pinch & Pan Gesture Recgnizer.
custom-view's content is Image control in forms.
I wanted to slide, pan-move and zoomable image gallery.
Gesture performance (pinch & zoom) was good.So , I added CarouselViewControl for sliding option. But , CarouselViewControl blocked my custom-view's Gesture
I don't know why blocked my Gesture-Recognizer.
I registered Recognizers in constructor
class Android_ZoomViewer : ContentView
{
....
public Android_ZoomViewer()
{
PinchGestureRecognizer pinchGesture = new PinchGestureRecognizer();
pinchGesture.PinchUpdated += PinchGesture_PinchUpdated;
GestureRecognizers.Add(pinchGesture);
var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += OnPanUpdated;
GestureRecognizers.Add(panGesture);
}
}
in CarouselPage.xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CarouselPage : ContentPage
{
public CarouselPage()
{
InitializeComponent();
var carousel = new CarouselViewControl();
ObservableCollection<Android_ZoomViewer> list= new ObservableCollection<Android_ZoomViewer>();
hymn.Add(new Android_ZoomViewer() { Content = new ImageView() });
hymn.Add(new Android_ZoomViewer() { Content = new ImageView() });
hymn.Add(new Android_ZoomViewer() { Content = new ImageView() });
((ImageView)hymn[0].Content).SetBinding(Image.SourceProperty,"img1");
((ImageView)hymn[1].Content).SetBinding(Image.SourceProperty, "img2");
((ImageView)hymn[2].Content).SetBinding(Image.SourceProperty, "img3");
carousel.ItemsSource = list;
in CarouselView, my Gesture Blocked ...
Related
I have a Xamarin.Forms app. I would like to remove/hide the back arrow in my navigation bars but keep the title. I was able to do it in iOS using the following code inside my NavigationPageRenderer:
UINavigationBar.Appearance.BackIndicatorImage = new UIImage();
UINavigationBar.Appearance.BackIndicatorTransitionMaskImage = new UIImage();
Is there any equivalent code for this in Android that I could use inside my renderer or in the MainActivity? I tried this.ActionBar.SetDisplayHomeAsUpEnabled(false); inside my MainActivity but the ActionBar always returns null. Below is my my MainActivity code:
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
if (Window != null)
{
Window.SetStatusBarColor(Android.Graphics.Color.Transparent);
}
this.ActionBar.SetDisplayHomeAsUpEnabled(false);
}
}
What I want my navigation bar to look like something like the image below (this is in my iOS app).
The back arrow is just the back button title: NavigationPage.SetBackButtonTitle(this, "\u25C3");
In my ContentPage:
public partial class HomeTabPage : ContentPage
{
public HomeTabViewModel vm;
public HomeTabPage()
{
InitializeComponent();
BindingContext = vm = new HomeTabViewModel(this);
NavigationPage.SetHasBackButton(this, false);
NavigationPage.SetBackButtonTitle(this, "\u25C3");
}
}
Solution:
You can define a custom view as navigationBar of your content on specific platform (Android).Refer to the following code.
public partial class Page1 : ContentPage
{
public Page1 ()
{
InitializeComponent ();
if(Device.RuntimePlatform=="Android")
{
NavigationPage.SetHasBackButton(this, false);
NavigationPage.SetTitleView(this, SetBackView("Title", "back"));
}
}
private void BackButton_Clicked(object sender, EventArgs e)
{
Navigation.PopAsync();
}
StackLayout SetBackView (string title,string backButtonContent)
{
Button backButton = new Button()
{
Text = backButtonContent,
TextColor = Color.White,
FontAttributes=FontAttributes.None,
BackgroundColor = Color.Transparent,
Margin = new Thickness(-20,0,0,0),
};
backButton.Clicked += BackButton_Clicked;
StackLayout stackLayout = new StackLayout
{
Children = {
backButton,
new Label{
HorizontalTextAlignment=TextAlignment.Center,
VerticalTextAlignment=TextAlignment.Center,
Text=title,
TextColor=Color.White,
BackgroundColor=Color.Transparent,
},
},
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.StartAndExpand,
Orientation = StackOrientation.Horizontal,
};
return stackLayout;
}
}
And the effect is just like the following ,you can set the content of page title and backButton as you want.
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).
In my Xamarin forms application I want to show a confirmation message when user clicks the back button from Main-page. Is there any way to achieve this?
I overrided the OnBackButtonPressed method in my MainPage. But still the app is closing while back key press. Here is my code
protected override bool OnBackButtonPressed ()
{
//return base.OnBackButtonPressed ();
return false;
}
You can override OnBackButtonPressed for any Xamarin.Form Page. But it only will work for the physical button in Android and Windows Phone devices.
protected override bool OnBackButtonPressed () {
DisplayAlert("title","message","ok");
return true;
}
For the virtual one, you will need to create CustomRenderers and to intercept the click handler. In iOS it can be tricky because the user can go back doing other actions (e.g. the swipe gesture). Once you intercept it you just need to create your Confirmation Message (which I assume that you know how to do it).
For iOS you can do something like this:
[assembly: ExportRenderer (typeof (YourPage), typeof (YourPageRenderer))]
namespace YourNamespace {
public class YourPageRenderer : PageRenderer {
public override void ViewWillAppear (bool animated) {
base.ViewWillAppear (animated);
Action goBack = () => page.DisplayAlert("title","message","ok");
var backButton = new NavBackButton (goBack);
navigationItem.LeftBarButtonItem = new UIBarButtonItem (backButton);
}
}
public class NavBackButton : UIView {
public NavBackButton (Action onButtonPressed) {
SetButton (onButtonPressed);
}
UILabel text;
UIImageView arrow;
void SetButton(Action onButtonPressed){
arrow = new UIImageView(new CGRect(-25,0, 50, 50)) {
Image = new UIImage("Images/back").ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
};
arrow.TintColor = Colors.DarkGreen.ToUIColor ();
text = new UILabel(new CGRect(arrow.Frame.Width + arrow.Frame.X -15, arrow.Frame.Height /2 - 10, 40, 20)) { Text = "Back" };
text.TextColor = Colors.DarkGreen.ToUIColor ();
Frame = new CGRect(0,0,text.Frame.Size.Width + arrow.Frame.Width, arrow.Frame.Height);
AddSubviews (new UIView[] { arrow, text });
var tapGesture = new UITapGestureRecognizer (onButtonPressed);
AddGestureRecognizer (tapGesture);
}
public override void TouchesBegan (Foundation.NSSet touches, UIEvent evt) {
base.TouchesBegan (touches, evt);
text.TextColor = UIColor.YourColor;
arrow.TintColor = UIColor.YourColor;
}
public override void TouchesEnded (Foundation.NSSet touches, UIEvent evt){
base.TouchesEnded (touches, evt);
arrow.TintColor = UIColor.YourColor;
text.TextColor = UIColor.YourColor;
}
}
}
PS You will need to provide an arrow image ("Images/back")
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.
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.