I have a scanner app build in Xamarin for Android and IOS.
When the scanner succeed I want to show a green screen of 0,5 seconds.
And when it fails I want to show a red screen.
But I can't find any code that allows me to create that screen.
I hope anyone here can push me in the right direction.
I think you will have a callback function when scanner succeed or fails.
In the callback function you can use BackgroundColor = Color.Red; to change the background.
Every page have the BackgroundColor property. For example I created a bottom by code and click the button to change the page background:
public App()
{
InitializeComponent();
var page1 = new ContentPage();
Button changeBgBt = new Button { Text = "change backgroud color", WidthRequest = 100, HeightRequest = 50, VerticalOptions=LayoutOptions.Center, HorizontalOptions = LayoutOptions.Center };
changeBgBt.Clicked += ChangeBgBt_Clicked;
var content = new StackLayout();
content.Children.Add(changeBgBt);
page1.Content = content;
MainPage = page1;
}
private void ChangeBgBt_Clicked(object sender, EventArgs e)
{
MainPage.BackgroundColor = Color.Red;
}
Related
I have been following the custom pin tutorial using Xamarin.Forms which I have linked below. I have finished implementing it and I have also moved onto adding pins to the map as well through tapping.
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/map/customized-pin
(side note: I am working almost exclusively with Xamarin.Forms and Android)
Currently, I am able to tap on the map and a new custom pin will be added at that location, which is great. What is not great is that I was unable to figure out how to get a tap and long hold gesture to work instead of just the normal tap. To try to combat this, and because I will eventually have to add these anyways, I am planning on adding a button that the user can press to initiate that they want to add a button to the map, and I will later add an undo button, and many others, etc.
The problem is, I have no idea how to get the result of what my toggle button state is from the custom render that I am using for the map. Where can I get the result of my toggle button and use it as a boolean towards whether to add a button or not?
Here is the toggle button code, which I took line by line from their example on this page:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/button
Here is the code where I add a custom pin just by a single tap:
private void GoogleMap_MapClick(object sender, GoogleMap.MapClickEventArgs e)
{
((CustomMap)Element).OnTap(new Position(e.Point.Latitude, e.Point.Longitude));
var addingPin = new CustomPin
{
Type = PinType.Place,
Position = new Position(e.Point.Latitude, e.Point.Longitude),
Address = " - need to possibly implement - ",
Id = "shelter",
Label = "Pin from tap",
Url = "http://www.redcross.org"
};
Map.Pins.Add(addingPin);
this.customPins.Add(addingPin);
}
I thought about making a custom button render but by my knowledge I can only apply one Android render to a content page at a time, and when I tried to add a custom button render to the map render then this method was not happy, as it was taking in some sort of Android Map View and not a button view:
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
NativeMap.InfoWindowClick -= OnInfoWindowClick;
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
customPins = formsMap.CustomPins;
Control.GetMapAsync(this);
}
}
Any help is greatly appreciated. Below I have included a pic of what my application looks like so far, along with the custom page that I am using as well.
using Hermes.Models;
using System;
using System.Collections.Generic;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
namespace Hermes
{
public class MapPage : ContentPage
{
public MapPage()
{
CustomMap customMap = new CustomMap()
{
HeightRequest = 100,
WidthRequest = 960,
VerticalOptions = LayoutOptions.FillAndExpand,
MapType = MapType.Street,
};
var examplePinSupplies = new CustomPin
{
Type = PinType.Place,
Position = new Position(42.02525, -93.65087),
Address = " - need to possibly implement - ",
Id = "supplies",
Label = "supplies",
Url = "https://www.redcross.org/store"
};
var examplePinMedical = new CustomPin
{
Type = PinType.Place,
Position = new Position(42.02290, -93.63912),
Address = " - need to possibly implement - ",
Id = "medical",
Label = "medical",
Url = "http://www.redcross.org"
};
var examplePinShelter = new CustomPin
{
Type = PinType.Place,
Position = new Position(42.02045, -93.60968),
Address = " - need to possibly implement - ",
Id = "shelter",
Label = "shelter",
Url = "http://www.redcross.org"
};
customMap.CustomPins = new List<CustomPin> { examplePinSupplies, examplePinMedical, examplePinShelter };
customMap.Pins.Add(examplePinSupplies);
customMap.Pins.Add(examplePinMedical);
customMap.Pins.Add(examplePinShelter);
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(42.025250, -93.650870), Distance.FromMiles(1.0)));
var addPin = new ToggleButton { Text = "Add pin" };
var buttons = new StackLayout
{
Orientation = StackOrientation.Horizontal,
Children = {
addPin
}
};
Content = new StackLayout
{
Spacing = 0,
Children = {
customMap,
buttons
}
};
}
}
}
What I am trying to do: I am trying to tap the 'add pin' toggle button, and then the map will allow me to only add one pin on the map by tapping, and then any other consecutive taps that are not on another pin will not add another pin to the map.
I have a custom animation that expands a Cell inside a TableView. I also refresh the tableView size before/after the animation as appropriate. This works on UWP, and I don't have a Mac yet, so I can't test it on IOS.
This doesn't work at all on Android. It does not refresh the tableRoot to update the size of it, nor does it seem to play the expanding animations.
I say the second part, because when I lock the tableview to the full size it doesn't play.
The animation itself is pretty straight forward:
private void AnimateLinearRowAppear(VisualElement visual, double targetHeight = 40, TableRoot _tableRoot, bool visible)
{
visual.IsVisible = visible;
TableRootRefresher(_tableRoot);
Animation _animation;
_animation = new Animation(
(d) => visual.HeightRequest = d, 0, targetHeight);
_animation.Commit(visual, "The Animation", 16, 250, Easing.Linear, (target, b) =>
{
_animation = null;
});
}
Any one have any ideas as to why it doesn't work on Android?
Unless I'm mistaken this is for cross platform development.
Do I have to write an interface and call each of my animations in a platform specific way?
Oh, this is the latest version of Xamarin 2.3.4.270.
Thanks for any help in advance!
I'm calling the animation from an event such as a specific picker selection or switch.
Switch.toggled += (sender, e) =>
{
AnimationChooser(celltochange,switch.toggle, tableRootCellIsPartOf);
}
AnimationChooser decides if we're playing the appearing or disappearing animation and is working correctly.
private void AnimationChooser(Cell celltoChange, bool stateOfSwitch, TableRoot _tableRoot)
{
var visual = (celltoChange as ViewCell).View
if(visual.IsVisible && stateOfSwitch)
{ AnimateLinearRowDissappear(visual, 40 ,_tableRoot, stateOfSwitch);}
else AnimateLinearRowAppear(visual,40,_tableRoot,stateOfSwitch);
}
TableRootRefresher(TableRoot _tableRoot)
{
Var tempRoot = _tableRoot;
_tableRoot = null;
_tableRoot = tempRoot:
}
The XAML:
<TableView>
<TableRoot x:Name="root">
<TableSection>
<SwitchCell x:Name="switch"/>
<EntryCell x:Name="toAppear" HieghtRequest="0" IsVisible="False"/>
</TableSection>
</TableRoot>
</TableView>
Here is a sample project.
I have used the below codesnippet animation working fine for me.
//animate changed the opacity from 1 to 0.
//XFtabbody is my UI elements
var animation = new Animation(v => XFTabBody.Opacity = v, 1, 0);
Action<double, bool> finished = animate;
animation.Commit(XFTabBody, "aa", 0, 100, Easing.Linear, finished);
void animate(double d, bool b)
{
XFTabBody.Children.Clear();
}
I want to know how I can display video from jpegs in Xamarin (all platforms).
My jpegs are being streamed from a http client stream sent by a popular video surveillance management software.
My jpegs are in the form of byte[] and I get about 10 jpegs/second. This format is imposed.
I tried rapidly changing the Source on a Image but it results in severe fliquering on Android. This seems to work on Windows phone but not so good performance.
How can I create a videoplayer for each one? Unless I am wrond, the existing components cannot do this.
Best,
Thank you Jason! Works great, very fluid rendering!!
Simply add the SkiaSharp.Views.Forms with NuGet to the project and voila!
Here is what that would look like in code (shared project):
// Content page initialization
private void InitUI() {
Title = "Xamavideo";
var button = new Button
{
Text = "Connect!"
};
Label label = new Label
{
Text = ""
};
var scroll = new ScrollView();
scroll.BackgroundColor = Color.Black;
Content = scroll;
var stack = new StackLayout
{
Padding = 40,
Spacing = 10
};
//Add a SKCanvasView item to the stack
var videoCanvas = new SKCanvasView
{
HeightRequest = 400,
WidthRequest = 600,
};
videoCanvas.PaintSurface += OnCanvasViewPaintSurface;
stack.Children.Add(videoCanvas);
}
//Create the event handler
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
// using (var stream = new SKManagedStream(fileStream))
if (lastFrame == null) return;
using (var canvas = surface.Canvas)
// use KBitmap.Decode to decode the byte[] in jpeg format
using (var bitmap = SKBitmap.Decode(lastFrame))
using (var paint = new SKPaint())
{
// clear the canvas / fill with black
canvas.DrawColor(SKColors.Black);
canvas.DrawBitmap(bitmap, SKRect.Create(640, 480), paint);
}
}
void UpdateFrame(VideoClient client){
//Use this to update the canvas:
byte[] lastFrame = client.imageBytes;
videoCanvas.InvalidateSurface();
}
In my Xamarin Forms app I have a WebView used as a form by inserting a div with contentEditable set to true. It all worked fine until the update to AppCompat styles.
Now, a strange white overlay (white square) appears when the user tries to write inside the WebView, that disappears when the keyboard is dismissed. In order to find the root cause of the problem I have created a sample project with just one page containing just a vertical stack layout containing another stack layout and the webview. What I have noticed is that this problem happens if the height of the internal stack layout is enough for the webview to be covered by the keyboard when it appears. In this case the webview is pushed up, and this strange overlay appears. The webview is fully functional, and it is possible to write text, even though it is hidden by this white square, that disappears when the keyboard is dismissed.
This is an example of a simple page that can be used to test the issue. The buttons have been added only to increase and decrease the size of the layout to show the problem more easily
public class MainPage : ContentPage
{
const string ContentEdit = #"<div contentEditable=""true"" style =""min-height: 200px"">";
const string ContentEditEnd = "</div>";
const string EmptyDocument = #"<body>" + ContentEdit + ContentEditEnd + #"</body>";
WebView webView;
public MainPage()
{
InitializePage();
}
void InitializePage()
{
webView = new WebView()
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
};
var button1 = new Button
{
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.CenterAndExpand,
Text = "-",
};
var button2 = new Button
{
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.CenterAndExpand,
Text = "+",
};
var tallLayout = new StackLayout()
{
Orientation = StackOrientation.Horizontal,
HeightRequest = 200,
BackgroundColor = Color.Lime,
Children = { button1, button2, },
};
button1.Clicked += (sender, e) => tallLayout.HeightRequest = tallLayout.Height - 20;
button2.Clicked += (sender, e) => tallLayout.HeightRequest = tallLayout.Height + 20;
var layout = new StackLayout
{
Orientation = StackOrientation.Vertical,
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Children = { tallLayout, webView },
};
Content = layout;
}
protected override void OnAppearing()
{
InitializeEmptyContent();
}
public void InitializeEmptyContent()
{
var htmlSource = new HtmlWebViewSource();
htmlSource.Html = EmptyDocument;
webView.Source = htmlSource;
}
}
I have tried to reproduce this simple layout also just using native Android, but it seems I don't have any similar bug. Is this a Xamarin Forms bug or am I doing something wrong?
In the end the problem was recognised as a Xamarin bug.
Right now i am implementing a custom Renderer for my Xamarin.Forms Label with which i can make use of the marquee scrolling features of the TextView.
What i want to do now is change the scrolling mode of the text from just going to the left endlessly to "bouncing" from side to side. (Kind of like this question i found regarding this subject: How to make a label scroll a word back and forth?) I have not found any resources online that talk about this. I would be very happy if you could give me a general idea of where to look or what to do.
Thank you for your time
Here is my marquee Custom-Renderer:
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
MarqueeLabel marqLabel = (MarqueeLabel)this.Element;
base.OnElementChanged(e);
if (marqLabel.shouldScroll)
{
Control.SetSingleLine(true);
Control.SetHorizontallyScrolling(true);
Control.Selected = true;
Control.Ellipsize = Android.Text.TextUtils.TruncateAt.Marquee;
Control.SetMarqueeRepeatLimit(-1);
}
}
If you can do the animations on the Xamarin.Forms level then you can save yourself quite a bit of work rather than implementing on each platform-specific level.
Try the following example that demonstrates some bouncing of a Label to and from the edges of the screen, as it may give you some ideas? Note it doesn't do it continuously in the example below.
StackLayout objStackLayout = new StackLayout()
{
Orientation = StackOrientation.Vertical,
};
Label objLabel = new Label();
objLabel.Text="Hello";
objLabel.HorizontalOptions = LayoutOptions.Start;
objStackLayout.Children.Add(objLabel);
Button objButton1 = new Button()
{
Text = "Animate"
};
objButton1.Clicked += (async (o2, e2) =>
{
double dblWidth = objStackLayout.Width - objLabel.Width;
//
await objLabel.TranslateTo(dblWidth, 0,1000, Easing.BounceIn);
await objLabel.TranslateTo(0,0,1000, Easing.BounceIn);
});
objStackLayout.Children.Add(objButton1);
This is not the good way to do that but I am sure this will solve your problem.
StackLayout objStackLayout = new StackLayout()
{
Orientation = StackOrientation.Vertical,
};
Label lblMarquee = new Label();
lblMarquee.Text = "This is marquee animation!!!";
lblMarquee.HorizontalOptions = LayoutOptions.Start;
objStackLayout.Children.Add(lblMarquee);
Button btnAnimate = new Button()
{
Text = "Stare Marquee Animation"
};
btnAnimate.Clicked += (async (o2, e2) =>
{
double dblWidth = objStackLayout.Width + lblMarquee.Width;
// Infinite loop
while (true)
{
lblMarquee.IsVisible = false;
await lblMarquee.TranslateTo(dblWidth / 2, 0, 500, Easing.SinIn);
lblMarquee.IsVisible = true;
await lblMarquee.TranslateTo(-(dblWidth / 2), 0, 10000, Easing.SinIn);
}
});
objStackLayout.Children.Add(btnAnimate);
Content = objStackLayout;
}
NOTE: You can remove the infinite loop and try the same with TPL that will be good way to handle never ending task instead of using infinite loop.