How generate the Renderer from a Maui element - custom-controls

I have a application where I need to extract the renderer from a Xamarin forms element, this is working fine Xamarin forms, I'm not sure how we can achieve this in MAUI, any inputs would be deeply appreciated. I'm doing this in renderer
public AView ConvertFormsToNative(Xamarin.Forms.View view, Rectangle size)
{
var vRenderer = Platform.CreateRendererWithContext(view, this.Context);
var viewGroup = vRenderer.View;
vRenderer.Tracker.UpdateLayout();
var layoutParams = new ViewGroup.LayoutParams((int)size.Width, (int)size.Height);
viewGroup.LayoutParameters = layoutParams;
view.Layout(size);
viewGroup.Layout(0, 0, (int)view.WidthRequest, (int)view.HeightRequest);
return viewGroup;
}
This specific line is helping me get the renderer from the forms element
var vRenderer = Platform.CreateRendererWithContext(view, this.Context);
Any inputs would be really helpfull

You can get the Renderer via below code:
var renderer=Platform.Android.AppCompat.Platform.CreateRendererWithContext(element, _context);
For more details, you can refer to maui code docs;

Related

cannot convert from UIKit.UIImage to ZXing.LuminanceSource - Xamarin iOS in Visual Studios 2017

All the examples I see are for Xamarin Forms, nothing for Xamarin for Visual Studios. I have an iOS app I'm developing with Xamarin for Visual Studio and need to read barcodes. I downloaded ZBar into Visual Studio 2017 from NuGet and installed it, no problem there. I access the camera and capture an image (barcode), no problem. However, there seems to be no way to convert the UIKit.UIIMage captured from the camera to a "ZXing.LuminanceSource" so it can be decoded. If someone could help point me in the right direction I would appreciate it. The code I have is fairly simple taken from the ZBar example included with the download:
IBarcodeReader scanPage = new BarcodeReader();
var result = scanPage.Decode(theImage); // the image is public and is set to the image returned by the camera. It's here I get the error in intellisense "cannot convert from UIKit.UIImage to ZXing.LuminanceSource"
Camera image return code:
[Foundation.Export("imagePickerController:didFinishPickingImage:editingInfo:")]
public void FinishedPickingImage(UIKit.UIImagePickerController picker, UIKit.UIImage image, Foundation.NSDictionary editingInfo)
{
theImage = MaxResizeImage(image, 540f, 960f);
picker.DismissModalViewController(false);
}
[Foundation.Export("imagePickerControllerDidCancel:")]
public void Canceled(UIKit.UIImagePickerController picker)
{
DismissViewController(true, null);
}
public static UIImage MaxResizeImage(UIImage sourceImage, float maxWidth, float maxHeight)
{
var sourceSize = sourceImage.Size;
var maxResizeFactor = Math.Min(maxWidth / sourceSize.Width, maxHeight / sourceSize.Height);
if (maxResizeFactor > 1) return sourceImage;
var width = maxResizeFactor * sourceSize.Width;
var height = maxResizeFactor * sourceSize.Height;
UIGraphics.BeginImageContext(new CGSize((nfloat)width, (nfloat)height));
sourceImage.Draw(new CGRect(0, 0, (nfloat)width, (nfloat)height));
var resultImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return resultImage;
}
}
I managed to resolve the issue with some help from #Jason, thanks Jason. I downloaded from NuGet and installed ZXing.Net.Mobile AND ZXing.Net.Mobile.Forms. You need both for Xamarin - Visual Studios. Removed all that camera code and replaced with 3 lines of code, plus I needed to add async to my button_TouchUpInside call.
In AppDelegate FinishedLaunching:
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// Override point for customization after application launch.
// If not required for your application you can safely delete this method
// Add this line to initialize ZXing
ZXing.Net.Mobile.Forms.iOS.Platform.Init();
return true;
}
Changed the button code to this, make button async to await scan result:
async partial void ScanBarCode_TouchUpInside(UIButton sender)
{
// Create scanner
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
// Store result of scan in var result, need to await scan
var result = await scanner.Scan();
// display bar code number in text field
Textbox_BarCode.Text = result.Text;
}
Works every time (thus far).

AVCapturePhotoSettings not accepting accept NSDictionary element

not sure what I am doing wrong, I wanna create a simple custom camera, I'm creating the AVCapturePhotoOutput attaching it to AVCaptureSession, then creating AVCapturePhotoSettings with minimum settings to make taking a picture work, see code below.
I get exception kCVPixelBufferPixelFormatTypeKey is not being define but it is indeed in the NSDictionary I am passing.
I need some light here, thanks
public void TakePicture()
{
var output = new AVCapturePhotoOutput();
_captureSession.AddOutput(output);
var settings = AVCapturePhotoSettings.Create();
var previewPixelType = settings.AvailablePreviewPhotoPixelFormatTypes.First();
var keys = new[]
{
new NSString("kCVPixelBufferPixelFormatTypeKey"),
new NSString("kCVPixelBufferWidthKey"),
new NSString("kCVPixelBufferHeightKey"),
};
var objects = new NSObject[]
{
// don't have to be strings... can be any NSObject.
previewPixelType,
new NSString("160"),
new NSString("160")
};
var dicionary = new NSDictionary<NSString, NSObject>(keys, objects);
settings.PreviewPhotoFormat = dicionary;
output.CapturePhoto(settings,this);
}
It is because kCVPixelBufferPixelFormatTypeKey is not available in Xamarin.
We should use CVPixelBuffer.PixelFormatTypeKey here . It will be convert to kCVPixelBufferPixelFormatTypeKey automatically when compiling.
The same reason for kCVPixelBufferWidthKey and kCVPixelBufferHeightKey , the api is CVPixelBuffer.WidthKey and CVPixelBuffer.HeightKey in Xamarin.iOS.

Xamarin forms (android project) error rendering image using Skia graphics library

I am trying to load and render an image using the skia graphics library in my xamarin forms solution. When I try to render the image (running the android project) I get the following error:
Value cannot be null. Parameter name: codec
here is the code:
void OnPainting(object sender, SKPaintSurfaceEventArgs e)
{
var surface = e.Surface;
var canvas = surface.Canvas;
canvas.Clear(SKColors.White);
var filename = "test.jpg";
using (var stream = new SKFileStream(filename))
using (var bitmap = SKBitmap.Decode(stream)) // the error occurs on this line
using (var paint = new SKPaint())
{
canvas.DrawBitmap(bitmap, SKRect.Create(200, 200), paint);
}
}
I cannot find any sample code online for xamarin. Any sample code or links would be much appreciated.
thanks in advance
Value cannot be null. Parameter name: codec
I think it is possible you get a null object here: using (var stream = new SKFileStream(filename)). I tried to created a demo, and it works fine.
XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:skiaviews="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
x:Class="FormsIssue6.Page1">
<Grid>
<skiaviews:SKCanvasView x:Name="mycanvas" PaintSurface="OnPainting" />
</Grid>
</ContentPage>
Code behind:
private void OnPainting(object sender, SkiaSharp.Views.Forms.SKPaintSurfaceEventArgs e)
{
var surface = e.Surface;
var canvas = surface.Canvas;
var assembly = typeof(Page1).GetTypeInfo().Assembly;
var fileStream = assembly.GetManifestResourceStream("YOUR-FILE-FULL-NAME");
// clear the canvas / fill with white
canvas.DrawColor(SKColors.White);
// decode the bitmap from the stream
using (var stream = new SKManagedStream(fileStream))
using (var bitmap = SKBitmap.Decode(stream))
using (var paint = new SKPaint())
{
// create the image filter
using (var filter = SKImageFilter.CreateBlur(5, 5))
{
paint.ImageFilter = filter;
// draw the bitmap through the filter
canvas.DrawBitmap(bitmap, SKRect.Create(640, 480), paint);
}
}
}
The file name in the code above should be like "YOUR PROJECT NAMESPACE"."File NAME", and this file is placed in PCL and build action of this file must be "Embedded Resource". For more information about working with file, you can refer to Files.
I cannot find any sample code online for xamarin. Any sample code or links would be much appreciated.
The package itself on Github has a code sample for Xamarin.Forms, you can refer to FormsSample.

NativeScript: Accessing native Android API

There is still something i don't get in accessing native Platform stuff with nativescript. Here is a simple snippet where i try to access a native gui element and add it to a page:
var PagesModule = require('ui/page');
var Application = require('application');
var StackLayout = require('ui/layouts/stack-layout').StackLayout;
exports.createPage = function createPage(args) {
var page = new PagesModule.Page;
page.actionBarHidden = true;
page.backgroundColor = '#F5F5F5';
page.backgroundSpanUnderStatusBar = false;
var textView = new android.widget.TextView(Application.android.currentContext);
var stackLayout = new StackLayout();
stackLayout.addChild(textView);
page.content = stackLayout;
return page;
}
I think i am missing something in the understanding of how nativescript interacts with the native platform.
The reason it is failing is because only "view" or "view" descendants can be assigned to "view" child or children.
You are creating a direct android component; but it isn't part of the NS framework, so the framework doesn't know what to do with it. When you create a visual component you descend your component from a view (or another view descendant). The NS version of the code should be:
var PagesModule = require('ui/page');
var Application = require('application');
var StackLayout = require('ui/layouts/stack-layout').StackLayout;
vat TextView = require('ui/text-view').TextView;
exports.createPage = function createPage(args) {
var page = new PagesModule.Page;
page.actionBarHidden = true;
page.backgroundColor = '#F5F5F5';
page.backgroundSpanUnderStatusBar = false;
var textView = new TextView();
var stackLayout = new StackLayout();
stackLayout.addChild(textView);
page.content = stackLayout;
return page;
}
If you are actually wanting to create your own component I would recommend you look at the UI/Switch it is probably the simplest example; but in a nutshell you need to subclass the view, on Android use the function _createUI to actually create the native component, and so in simplest terms it would be:
var View = require('ui/core/view').View;
function MyTextView() {
View.apply(this, arguments);
}
__extends(MyTextView, View);
Object.defineProperty(MyTextView.prototype, "android", {
get: function () {
return this._android;
},
enumerable: true,
configurable: true
});
MyTextView.prototype._createUI = function () {
this._android = new android.widget.TextView(Application.android.currentContext);
};
Then you can use new MyTextView() instead of the built in new TextView() function in the first code sample.
Please note with this component, because we haven't defined any additional helper function, to set and get the text you would have to do things like
var x = page.GetViewById('myTextId').android.setText("Some Value");
and to access the native underlying control and its android properties.
Please note I have a whole blog article on some of this at http://fluentreports.com/blog/?p=167 (And many other articles on the site about NS)

How to show ActivityIndicator in the middle of the screen?

I've created an activity indicator and added it to StackLayout and when I make it running, in the emulator it shows in the top right corner Android 4.4 and in iOS no show and in Android 6 phone, it don't show.
var indicator = new ActivityIndicator()
{
Color = Color.Blue,
};
indicator.SetBinding(ActivityIndicator.IsVisibleProperty, "IsBusy", BindingMode.OneWay);
indicator.SetBinding(ActivityIndicator.IsRunningProperty, "IsBusy", BindingMode.OneWay);
AbsoluteLayout.SetLayoutFlags(indicator, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(indicator, new Rectangle(0.5, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
mainLayout.Children.Add(indicator);
I want to show the activity indicator to the center of the screen because the operation takes time to complete.
The indicator that you are seeing in the status bar is the default behavior of the IsBusy property of the base page class. The reason your code isn't working is because you are attempting to bind visibility of your ActivityIndicator to that property - but you aren't specifying a binding source. If you look in your debugger's application output log then you will probably see messages along the lines of "Property 'IsBusy' not found on type 'Object'".
To fix it, you simply need to point the Binding Context of each binding to the form. Give this a try:
public partial class App : Application
{
public App ()
{
var mainLayout = new AbsoluteLayout ();
MainPage = new ContentPage {
Content = mainLayout
};
var containerPage = Application.Current.MainPage;
var indicator = new ActivityIndicator() {
Color = Color.Blue,
};
indicator.SetBinding(VisualElement.IsVisibleProperty, new Binding("IsBusy", BindingMode.OneWay, source: containerPage));
indicator.SetBinding(ActivityIndicator.IsRunningProperty, new Binding("IsBusy", BindingMode.OneWay, source: containerPage));
AbsoluteLayout.SetLayoutFlags(indicator, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(indicator, new Rectangle(0.5, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
mainLayout.Children.Add(indicator);
containerPage.IsBusy = true;
}
}
You add your activity indicator to stack layout, but you are setting Absolute layout LayoutFlags, they won't work.
to be able to achieve what you want, you need suck structure
AbsoluteLayout
StackLayout
ActivityIndicator
mainLayout should be AbsoluteLayout, all content should be contained in nested StackLayout.

Resources