i have created custom renderer of picker for android.but arrow image is overlapping picker text.as shown in below screenshot
here is my code
public class AndroidCutomPicker : PickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Picker> e)
{
base.OnElementChanged(e);
if (Control != null && this.Element != null)
{
Control.Background = AddPickerStyles();
Control.SetLines(1);
//Control.TextSize *= 0.25f;
}
}
public LayerDrawable AddPickerStyles()
{
ShapeDrawable border = new ShapeDrawable();
border.Paint.Color = Android.Graphics.Color.Gray;
border.SetPadding(10, 10, 10, 10);
border.Paint.SetStyle(Paint.Style.Stroke);
Drawable[] layers = { border, GetDrawable() };
LayerDrawable layerDrawable = new LayerDrawable(layers);
layerDrawable.SetLayerInset(0, 0, 0, 0, 0);
return layerDrawable;
}
private BitmapDrawable GetDrawable()
{
var drawable = ContextCompat.GetDrawable(this.Context, Resource.Drawable.dropdownarrow);
var bitmap = ((BitmapDrawable)drawable).Bitmap;
var result = new BitmapDrawable(Resources, Bitmap.CreateScaledBitmap(bitmap, 70, 70, true));
result.Gravity = Android.Views.GravityFlags.Right;
return result;
}
}
please help.
thank you
Facing the same problem and finding this question but finally i find a solution that is adding a padding where you want for me the padding is related to the size of the element so i make it like this
this.Control.SetPadding((int)(element.Width / 5), Control.PaddingTop, Control.PaddingRight, Control.PaddingBottom);
but if u have a specific constant binding u can do like this
this.Control.SetPadding(Control.PaddingLeft+XXX, Control.PaddingTop+xxx, Control.PaddingRight+xxx, Control.PaddingBottom+xxx);
Related
I have created a custom renderer for a frame to have rounded corners only on 2 sides. The code works fine in Android but in iOS the rounded corners are getting trimmed if the background color of frame is white and border color is blue like below image.
Custom Renderer IOS
public class CustomFrameRenderer : FrameRenderer
{
public override void LayoutSubviews()
{
base.LayoutSubviews();
UpdateCornerRadius();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == nameof(CustomFrame.CornerRadius) ||
e.PropertyName == nameof(CustomFrame))
{
UpdateCornerRadius();
}
}
// A very basic way of retrieving same one value for all of the corners
private double RetrieveCommonCornerRadius(CornerRadius cornerRadius)
{
var commonCornerRadius = cornerRadius.TopLeft;
if (commonCornerRadius <= 0)
{
commonCornerRadius = cornerRadius.TopRight;
if (commonCornerRadius <= 0)
{
commonCornerRadius = cornerRadius.BottomLeft;
if (commonCornerRadius <= 0)
{
commonCornerRadius = cornerRadius.BottomRight;
}
}
}
return commonCornerRadius;
}
private UIRectCorner RetrieveRoundedCorners(CornerRadius cornerRadius)
{
var roundedCorners = default(UIRectCorner);
if (cornerRadius.TopLeft > 0)
{
roundedCorners |= UIRectCorner.TopLeft;
}
if (cornerRadius.TopRight > 0)
{
roundedCorners |= UIRectCorner.TopRight;
}
if (cornerRadius.BottomLeft > 0)
{
roundedCorners |= UIRectCorner.BottomLeft;
}
if (cornerRadius.BottomRight > 0)
{
roundedCorners |= UIRectCorner.BottomRight;
}
return roundedCorners;
}
private void UpdateCornerRadius()
{
var cornerRadius = (Element as CustomFrame)?.CornerRadius;
if (!cornerRadius.HasValue)
{
return;
}
var roundedCornerRadius = RetrieveCommonCornerRadius(cornerRadius.Value);
if (roundedCornerRadius <= 0)
{
return;
}
var roundedCorners = RetrieveRoundedCorners(cornerRadius.Value);
var path = UIBezierPath.FromRoundedRect(Bounds, roundedCorners, new CGSize(roundedCornerRadius, roundedCornerRadius));
var mask = new CAShapeLayer { Path = path.CGPath };
NativeView.Layer.Mask = mask;
//NativeView.Layer.CornerRadius = 0;
NativeView.ClipsToBounds = true;
NativeView.Layer.MaskedCorners = (CoreAnimation.CACornerMask)3;
}
}
Can someone please help me to resolve below issue.
Thanks.
You could check the following code
private void UpdateCornerRadius()
{
var cornerRadius = (Element as Frame)?.CornerRadius;
if (!cornerRadius.HasValue)
{
return;
}
var roundedCornerRadius = RetrieveCommonCornerRadius(cornerRadius.Value);
if (roundedCornerRadius <= 0)
{
return;
}
var roundedCorners = RetrieveRoundedCorners(cornerRadius.Value);
NativeView.Layer.MasksToBounds = true;
var path = UIBezierPath.FromRoundedRect(Bounds, roundedCorners, new CGSize(roundedCornerRadius, roundedCornerRadius));
var mask = new CAShapeLayer { Path = path.CGPath };
mask.Frame = Bounds;
mask.LineWidth = 1;
mask.StrokeColor = UIColor.SystemBlueColor.CGColor; // border color
mask.FillColor = UIColor.Clear.CGColor; // bg color , you need to set it as clear otherwise it will cover its child element
mask.ShadowRadius = 0;
NativeView.Layer.AddSublayer(mask);
// NativeView.Layer.MaskedCorners = (CoreAnimation.CACornerMask)3;
}
A mask takes a layer, and trim that visual to match the mask.
So if a layer is a rectangle with black borders, and your mask is an oval,
an oval will appear with the color of the rectangle that it masks.
But it will not round those rectangle borders, just cut them out.
What you need to do instead is to build a layer that will replace NativeView.Layer
With your rounded rectangle, without using the mask.
Or change those values on the elements in the layer that already exist, directly.
I build an application that users can load a report and draw on screen for highlight and share some information (as an image). I develop this feature using Rg.Plugins.Popup.Pages.PopupPage and SkiaSharp. The popup page has a transparent background and a sharecontent button. Users draw in the popup page.
In Android, this works fine because I can take a screeshot of the entire screen using currentview.Window.DecorView.RootView, but in iOS when I take a screenshot the image get a black background. I use the following code to take the screenshot:
public void ShareContent(string imageName)
{
UIGraphics.BeginImageContextWithOptions(new CoreGraphics.CGSize(UIScreen.MainScreen.Bounds.Width, UIScreen.MainScreen.Bounds.Height), false, 0);
UIImage capture = UIApplication.SharedApplication.KeyWindow.Capture();
UIGraphics.EndImageContext();
var activityItems = new[] { capture };
var activityController = new UIActivityViewController(activityItems, null);
var topController = UIApplication.SharedApplication.KeyWindow.RootViewController;
while (topController.PresentedViewController != null)
{
topController = topController.PresentedViewController;
}
topController.PresentViewController(activityController, true, () => { });
}
How can I draw an image with a transparent background in Xamarin iOS?
Codebehind of PopupPage in shared project
public partial class DrawAndSharePage : Rg.Plugins.Popup.Pages.PopupPage
{
Dictionary<long, SKPath> inProgressPaths = new Dictionary<long, SKPath>();
List<SKPath> completedPaths = new List<SKPath>();
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Blue,
StrokeWidth = 10,
StrokeCap = SKStrokeCap.Round,
StrokeJoin = SKStrokeJoin.Round
};
public DrawAndSharePage()
{
BackgroundColor = new Color(0, 0, 0, 0.1);
InitializeComponent();
}
private async void BtnClose_Clicked(object sender, System.EventArgs e)
{
await Rg.Plugins.Popup.Services.PopupNavigation.Instance.PopAllAsync();
}
void OnTouchEffectAction(object sender, TouchActionEventArgs args)
{
switch (args.Type)
{
case TouchActionType.Pressed:
if (!inProgressPaths.ContainsKey(args.Id))
{
SKPath path = new SKPath();
path.MoveTo(ConvertToPixel(args.Location));
inProgressPaths.Add(args.Id, path);
canvasView.InvalidateSurface();
}
break;
case TouchActionType.Moved:
if (inProgressPaths.ContainsKey(args.Id))
{
SKPath path = inProgressPaths[args.Id];
path.LineTo(ConvertToPixel(args.Location));
canvasView.InvalidateSurface();
}
break;
case TouchActionType.Released:
if (inProgressPaths.ContainsKey(args.Id))
{
completedPaths.Add(inProgressPaths[args.Id]);
inProgressPaths.Remove(args.Id);
canvasView.InvalidateSurface();
}
break;
case TouchActionType.Cancelled:
if (inProgressPaths.ContainsKey(args.Id))
{
inProgressPaths.Remove(args.Id);
canvasView.InvalidateSurface();
}
break;
}
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKCanvas canvas = args.Surface.Canvas;
canvas.Clear();
foreach (SKPath path in completedPaths)
{
canvas.DrawPath(path, paint);
}
foreach (SKPath path in inProgressPaths.Values)
{
canvas.DrawPath(path, paint);
}
}
SKPoint ConvertToPixel(Point pt)
{
return new SKPoint((float)(canvasView.CanvasSize.Width * pt.X / canvasView.Width),
(float)(canvasView.CanvasSize.Height * pt.Y / canvasView.Height));
}
private void OnTouchEffectAction(object sender, object args)
{
}
}
I'm using the snippet of code in this answer to remove the spacing between icons, and it seems to remove also the padding to the right in the NavigationBar. The problem is that after screen orientation changes of after I push or pop pages in and out of the navigation stack the padding to the right reappears.
Why is this padding removed the first time the custom renderer adds the custom views?
Is there a way to remove the padding altogether?
Update
Removing the constraints with negative constants, as suggested in the answer below, seems to work at first but those are put back at some point.
The way to remove the padding is difference between iOS7+ and iOS11.
On iOS7+:
We can remove it by adding a UIBarButtonSystemItem.FixedSpace like:
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
var navigationItem = this.NavigationController.TopViewController.NavigationItem;
List<UIBarButtonItem> list = new List<UIBarButtonItem>();
foreach (var rightItem in navigationItem.RightBarButtonItems)
{
var button = new UIButton(new CGRect(0, 0, 32, 32));
button.SetImage(rightItem.Image, UIControlState.Normal);
FieldInfo fi = rightItem.GetType().GetField("clicked", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
Delegate del = (Delegate)fi.GetValue(rightItem);
button.TouchUpInside += (EventHandler)del;
UIBarButtonItem item = new UIBarButtonItem(button);
list.Add(item);
}
if (!UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
UIBarButtonItem negativeSpacer = new UIBarButtonItem(UIBarButtonSystemItem.FixedSpace);
negativeSpacer.Width = -16;
list.Insert(0, negativeSpacer);
}
this.NavigationController.TopViewController.NavigationItem.RightBarButtonItems = list.ToArray();
}
On iOS 11:
The navigationBar on iOS11 has some difference, so we could achieve this by modifying something in the method ViewDidLayoutSubviews() and ViewWillAppear():
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
tryToRelayout();
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
... ...//code above
tryToRelayout();
}
void tryToRelayout()
{
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
UINavigationItem item = NavigationController.TopViewController.NavigationItem;
var array = item.RightBarButtonItems;
if (array != null)
{
UIBarButtonItem buttonItem = array[0];
if (buttonItem.CustomView.Superview != null)
{
UIView view = buttonItem.CustomView.Superview.Superview.Superview;
var arrayConstraint = view.Constraints;
foreach (NSLayoutConstraint constant in arrayConstraint)
{
if (constant.Constant < 0)
{
constant.Constant = 0;
}
}
}
}
}
}
I am validating the input of my text field, which is of TextEdit type, using the Validating event. But the error icon is being displayed outside of the text field (second pic) rather than within it (first pic).
I've tried ErrorIconAlignment and it doesn't work. The icon is still being displayed outside of the text. Are there any other ways to have it displayed within the text field?
Thanks.
there is not a property allowing that.
but you can do this with the following code:
I created 2 buttons, 1 setErrorButton for set error an 2nd button for clear error with the SetError method, unwanted method CreatePictureEdit
private void setErrorButton_Click(object sender, EventArgs e)
{
SetError(textEdit1, "Error1");
textEdit1.Properties.MaskBoxPadding = new Padding(12, 0, 0, 0); //to put the cursor after the error image
}
private void clearErrorButto_Click(object sender, EventArgs e)
{
SetError(textEdit1, "");
textEdit1.Properties.MaskBoxPadding = new Padding(0, 0, 0, 0);
}
public static void SetError(Control ctrl, string errorText)
{
Form f = ctrl.FindForm();
if (errorText == string.Empty)
{
if (ctrl.Tag != null && ctrl.Tag is PictureEdit)
{
f.Controls.Remove(ctrl.Tag as PictureEdit);
return;
}
else
return;
}
PictureEdit edit = CreatePictureEdit(ctrl, errorText);
f.Controls.Add(edit);
ctrl.Tag = edit;
edit.BringToFront();
}
private static PictureEdit CreatePictureEdit(Control ctrl, string errorText)
{
PictureEdit edit = new PictureEdit();
Image image = BaseEdit.DefaultErrorIcon;
edit.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
edit.BackColor = Color.Transparent;
edit.Image = image;
edit.ToolTip = errorText;
edit.ToolTipIconType = DevExpress.Utils.ToolTipIconType.Error;
edit.Properties.SizeMode = DevExpress.XtraEditors.Controls.PictureSizeMode.Squeeze;
edit.Location = new Point(ctrl.Bounds.Left + 3, ctrl.Bounds.Y + 1);
edit.Size = new Size(image.Width, ctrl.Bounds.Height - 2);
edit.BackColor = Color.White;
return edit;
}
you can change the location property values and size of the image if the icon is not adjusted properly on the TextEdit
On a DataGrid, setting alternatingItemColors will apply the color scheme to all of the columns of that grid. I'm looking for a way to define different alternating colors for each column. Is there a baked in way to do this?
Have a look on this:http://blog.flexexamples.com/2008/09/24/setting-background-colors-on-a-datagrid-column-in-flex/
I hope this would be helpful for you ;)
public class BlocksTable extends DataGrid
{
public static const VALID_COLOR:uint = 0xDBAB21;
public static const INVALID_COLOR:uint = 0xC7403E;
public function BlocksTable()
{
super();
}
override protected function drawRowBackground(s:Sprite, rowIndex:int, y:Number, height:Number, color:uint, dataIndex:int):void
{
var contentHolder:ListBaseContentHolder = ListBaseContentHolder(s.parent);
var background:Shape;
if (rowIndex < s.numChildren)
{
background = Shape(s.getChildAt(rowIndex));
}
else
{
background = new FlexShape();
background.name = "background";
s.addChild(background);
}
background.y = y;
// Height is usually as tall is the items in the row, but not if
// it would extend below the bottom of listContent
var height:Number = Math.min(height,
contentHolder.height -
y);
var g:Graphics = background.graphics;
g.clear();
var fillColor:uint;
if(dataIndex < this.dataProvider.length)
{
if(this.dataProvider.getItemAt(dataIndex).IS_VALID)
{
fillColor = VALID_COLOR;
}
else
{
fillColor = INVALID_COLOR;
}
}
else
{
fillColor = color;
}
g.beginFill(fillColor, getStyle("backgroundAlpha"));
g.drawRect(0, 0, contentHolder.width, height);
g.endFill();
}
}