How to remove children from a UIView in Xamarin? - xamarin

I've this...
public partial class ViewController : UIViewController
{
UIView[] seqPages;
...
}
private void loadApp()
{
int seqCount=5;
for (int i = 0; i < seqCount; i++)
{
seqPages[i] = new UIView()
{
Frame = new CoreGraphics.CGRect(0, 0, vpWidth, vpHeight)
};
string s = app.sequence[i];
var img = UIImage.FromFile("pages/myimg.png");
UIImageView imgView = new UIImageView(new CoreGraphics.CGRect(0, 0, 1000, 1000));
imgView.Image = img;
imgView.ContentMode = UIViewContentMode.ScaleAspectFit;
seqPages[i].Add(imgView);
mainContainer.Add(seqPages[i]);
}
}
private void removePage(index){
//Remove the children of seqPages UIVIew array
}
So,on the comment "//Remove the children of seqPages UIVIew array" I need something like : seqPages[index].removeAllChildren();
I was unable to find on Google how to archive this. Can anybody help me ?

UIView has a RemoveFromSuperview method that will remove it from its "parent":
foreach (var view in this.View.Subviews)
{
view.RemoveFromSuperview();
}

Related

MvvmCross iOS UILabel AttributedText with Language converter

I create a custom control for UILabel with custom Kern parameter.
[Register("CustomLabelView"), DesignTimeVisible(true)]
public class CustomLabelView : UILabel
{
private float _textLetterSpacing;
public CustomLabelView(IntPtr handle) : base(handle)
{
}
[Export("TextLetterSpacing"), Browsable(true)]
public float TextLetterSpacing
{
get => _textLetterSpacing;
set
{
_textLetterSpacing = value;
SetNeedsDisplay();
}
}
public CustomLabelView()
{
Initialize();
}
public override void AwakeFromNib()
{
// Called when loaded from xib or storyboard.
Initialize();
}
void Initialize()
{
NSRange range = new NSRange(0, Text.Length);
var attributes = AttributedText.GetCoreTextAttributes(0, out range);
var attributedTitle = new NSAttributedString(Text, new CTStringAttributes() { KerningAdjustment = TextLetterSpacing, ForegroundColor = TextColor.CGColor, UnderlineStyle = attributes.UnderlineStyle });
AttributedText = attributedTitle;
SetNeedsDisplay();
}
}
I bind text to this control with language converter
set.Bind(CustomLabelView)
.For(c => c.Text)
.To(vm => vm.TextSource)
.WithConversion("Language", "AgreementText");
and underline property doesn't apply for bound text. Also I tried AttributedText property instead of Text. No any changes.
My LinkerPleaseInclude file contains this lines
public void Include(UILabel label)
{
label.Text = label.Text + "";
label.AttributedText = new NSAttributedString(label.AttributedText.ToString() + "");
}
Any ideas how to sort it out?
I changed the UnderlineStyle property's value to one of the enumeration of CTUnderlineStyle and it works for me.
namespace CoreText
{
//
// Summary:
// Specifies the style of an underline ornament.
//
// Remarks:
// To be added.
public enum CTUnderlineStyle
{
None = 0,
Single = 1,
Thick = 2,
Double = 9
}
}
Here is my code:
void Initialize()
{
this.Text = "This is some formatted text";
NSRange range = new NSRange(0, Text.Length);
var attributes = AttributedText.GetCoreTextAttributes(0, out range);
var attributedTitle = new NSAttributedString(Text, new CTStringAttributes() { KerningAdjustment = TextLetterSpacing, ForegroundColor = TextColor.CGColor, UnderlineStyle = CTUnderlineStyle.Single });
AttributedText = attributedTitle;
SetNeedsDisplay();
}
The underline appears,is this you want?
I just put Initialize method into Draw for my CustomLabel.
Here is the solution:
public override void Draw(CGRect rect)
{
Initialize();
base.Draw(rect);
}
private void Initialize()
{
var attributes = AttributedText.GetCoreTextAttributes(0, out _);
AttributedText = new NSMutableAttributedString(Text,
new CTStringAttributes
{
KerningAdjustment = TextLetterSpacing, Font = attributes.Font,
UnderlineStyle = attributes.UnderlineStyle
});
}

Xamarin Forms Custom Renderer iOS UICollectionView scrolling in both directions / horizontal – vertical scrolling

Xamarin Forms Custom Renderer iOS UICollectionView scrolling in both directions / horizontal – vertical scrolling
Intention: Implementation of an interactive Grid which scroll horizontally and vertically .
Problem:
The grid scrolls in both direction that much laggy. After scrolling with the finger you have to wait some seconds to see an reaction of the app.
We have implemented an UICollectionView in the same way in an native swift project, and it scrolls fluently. So I think the problem is rather the way of implementation than the rendering process.
With instruments I could find out that the CoreFoundation(RunLoops) cost the most of time(11s). So I guess its a threading problem.
Why I need to customize the UICollectionViewLayout to achieve horizontal scrolling? Because I need the ability to modify the width of single cells and other customizations too.
So the only way for scrolling in both direction I see, is to customize the UICollectionViewLayout.
Implementation:
Xamarin.Forms Project:
Create Custom Control (MyGrid) in Xamarin Forms, which extends from View Class:
public class MyGrid : View
{
public MyGrid() : base()
{
}
}
Use Custom Control ( MyGrid) in Xamarin Forms ContentPage):
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:GridDemo"
x:Class="GridDemo.GridDemoPage">
<ContentPage.Content>
<local:MyGrid
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
BackgroundColor="White"/>
</ContentPage.Content>
</ContentPage>
Xamarin.iOS Project:
Implement Custom Renderer for MyGrid Class in iOS project:
[assembly: ExportRenderer(typeof(MyGrid), typeof(MyGridRenderer))]
namespace GridDemo.iOS
{
public class MyGridRenderer : ViewRenderer<MyGrid, IOSGrid>
{
public MyGridRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<MyGrid> e)
{
base.OnElementChanged(e);
if (Control == null)
{
MyGrid myGrid = (MyGrid)e.NewElement;
List<List<string>> values = myGrid.Source;
var list = new List<CustomIOSGridCell>();
var column = 0;
var row = 0;
var maxColumnLength = new int[myGrid.ColumnCount];
for (int i = 0; i < myGrid.RowCount; i++)
{
for (int j = 0; j < myGrid.ColumnCount; j++)
{
var array = values[i];
var stringLength = array.Aggregate("", (max, cur) => max.Length > cur.Length ? max : cur);
if (stringLength.Length > maxColumnLength[j])
{
maxColumnLength[j] = stringLength.Length;
}
list.Add(new CustomIOSGridCell(values[i][j));
}
}
var grid = new IOSGrid(this.Bounds, new IOSGridLayout(myGrid.ColumnCount, myGrid.RowCount, maxColumnLength));
grid.AddValues(list, myGrid.ColumnCount, myGrid.RowCount);
SetNativeControl(grid);
}
if (e.OldElement != null)
{
// Unsubscribe from event handlers and cleanup any resources
}
if (e.NewElement != null)
{
// Configure the control and subscribe to event handlers
}
}
}
}
Implement native control(iOSGrid), the corresponding Control to Custom Xamarin Forms Control (MyGrid):
public class IOSGrid : UICollectionView
{
List<CustomIOSGridCell> values = new List<CustomIOSGridCell>();
public IOSGrid(CGRect frame, IOSGridLayout collectionViewLayout) : base(frame, collectionViewLayout)
{
this.RegisterClassForCell(typeof(CustomCollectionViewCell), CustomCollectionViewCell.CellID);
BackgroundColor = UIColor.Blue;
}
public void AddValues(List<CustomIOSGridCell> values, int columncount, int rowCount)
{
this.values.AddRange(values);
this.Source = new CustomCollectionSource(this.values, rowCount, columncount);
this.ReloadData();
}
}
Implement Custom UICollectionViewLayout for IOSGrid(UICollectionView) to provide horizontal AND vertical scrolling
public class IOSGridLayout : UICollectionViewLayout
{
private Timer timer;
enum Direction { up, down ,leftRight, none }
int columnsCount = 0;
int rowCount = 0;
CoreGraphics.CGSize[] itemsSize = null;
CoreGraphics.CGSize contentSize = CoreGraphics.CGSize.Empty;
int[] maxLength;
public CGRect currentRect = CGRect.Empty;
CGPoint currentCorner = new CGPoint(-1, -1);
UICollectionViewLayoutAttributes[,] itemAttributes;
public IOSGridLayout(int columnsCount, int rowCount, int[] maxLength)
{
this.columnsCount = columnsCount;
this.rowCount = rowCount;
this.maxLength = maxLength;
itemAttributes = new UICollectionViewLayoutAttributes[rowCount, columnsCount];
}
public override void PrepareLayout()
{
if (CollectionView == null) return;
var collectionView = CollectionView;
if (collectionView.NumberOfSections() == 0) return;
if (itemAttributes.Length != collectionView.NumberOfSections())
{
generateItemAttributes(collectionView);
return;
}
for (int section = 0; section < collectionView.NumberOfSections(); section++)
{
for (int item = 0; item < collectionView.NumberOfItemsInSection(section); item++)
{
if (section != 0 && item != 0)
{
continue;
}
var attributes = LayoutAttributesForItem(NSIndexPath.FromItemSection(item, section)); }
}
}
public override CGSize CollectionViewContentSize
{
get { return contentSize; }
}
public override UICollectionViewLayoutAttributes LayoutAttributesForItem(NSIndexPath indexPath)
{
return itemAttributes[indexPath.Section, indexPath.Row];
}
public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect(CGRect rect)
{
var attributes = new List<UICollectionViewLayoutAttributes>();
// calculate actual shown attributes
return attributes.ToArray();
}
public override bool ShouldInvalidateLayoutForBoundsChange(CGRect newBounds)
{
return true;
}
private void generateItemAttributes(UICollectionView collectionView)
{
if (itemsSize?.Length != columnsCount)
{
CalculateItemSizes();
}
var column = 0;
nfloat xOffset = 0;
nfloat yOffset = 0;
nfloat contentWidth = 0;
itemAttributes = new UICollectionViewLayoutAttributes[rowCount, columnsCount];
var se = collectionView.NumberOfSections();
for (int section = 0; section < rowCount; section++)
{
var sectionAttributes = new UICollectionViewLayoutAttributes[columnsCount];
for (int index = 0; index < columnsCount; index++)
{
var itemSize = itemsSize[index];
var indexPath = NSIndexPath.FromItemSection(index, section);
var attributes = UIKit.UICollectionViewLayoutAttributes.CreateForCell(indexPath);
attributes.Frame = new CGRect(xOffset, yOffset, itemSize.Width, itemSize.Height).Integral();
if (section == 0)
{
var frame = attributes.Frame;
frame.Y = collectionView.ContentOffset.Y;
attributes.Frame = frame;
}
if (index == 0)
{
var frame = attributes.Frame;
frame.X = collectionView.ContentOffset.X;
attributes.Frame = frame;
}
sectionAttributes[index]=attributes;
xOffset += itemSize.Width;
column += 1;
if (column == columnsCount)
{
if (xOffset > contentWidth)
{
contentWidth = xOffset;
}
column = 0;
xOffset = 0;
yOffset += itemSize.Height;
}
}
for (int i = 0; i < sectionAttributes.Length; i++)
{
itemAttributes[section, i] = sectionAttributes[i];
}
}
var attr = itemAttributes[rowCount-1,columnsCount-1];
if (attr != null)
{
contentSize = new CGSize(contentWidth, attr.Frame.GetMaxY());
}
}
private void CalculateItemSizes()
{
itemsSize = new CGSize[columnsCount];
for (int index = 0; index < columnsCount; index++)
{
itemsSize[index] = SizeForItemWithColumnIndex(index);
}
}
private CGSize SizeForItemWithColumnIndex(int index)
{
// CollectionView.CellForItem()
string text = "";
for (int i = 0; i < maxLength[index]; i++)
{
text += "M";
}
NSString ma = new NSString(text);
var size = ma.StringSize(UIFont.SystemFontOfSize(14));
size.Height = 35;
return size;
}
}
Implement Custom UICollectionViewSource for IOSGrid(UICollectionView):
public class CustomCollectionSource : UICollectionViewSource
{
private readonly List<CustomIOSGridCell> values = new List<CustomIOSGridCell>();
private readonly int rowCount = 0;
private readonly int columnCount = 0;
public CustomCollectionSource(List<CustomIOSGridCell> values, int rowCount, int columnCount)
{
this.values = values;
this.rowCount = rowCount;
this.columnCount = columnCount;
}
public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
return rowCount;
}
public override nint NumberOfSections(UICollectionView collectionView)
{
return columnCount;
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var cell = (CustomCollectionViewCell)collectionView.DequeueReusableCell(CustomCollectionViewCell.CellID, indexPath);
cell.UpdateCell(values[indexPath.Row].Text);
return cell;
}
}
Implement Custom UICollectionViewCell for IOSGrid(UICollectionView):
public class CustomCollectionViewCell : UICollectionViewCell
{
public UILabel mainLabel;
public static NSString CellID = new NSString("customCollectionCell");
[Export("initWithFrame:")]
public CustomCollectionViewCell(CGRect frame) : base(frame)
{
// Default
ContentView.Layer.BorderColor = UIColor.Blue.CGColor;
ContentView.Layer.BorderWidth = 1.0f;
ContentView.Layer.BackgroundColor = UIColor.White.CGColor;
mainLabel = new UILabel();
ContentView.AddSubview( mainLabel );
}
public void UpdateCell(string text)
{
mainLabel.Text = text;
mainLabel.Frame = new CGRect(5, 5, ContentView.Bounds.Width, 26);
}
}

How to Add Content Page to Segment Control in IOS Xamarin.Forms

I have used Segmented Control in my application. I don't know how to add two content pages to Segment control like a tabbed page. I have attached the sample file. Please give any suggestion Link for Sample Application
Sample Code:
public partial class SamplePage : ContentPage
{
SegmentedControl segControl;
SegmentedControlOption optionOne;
SegmentedControlOption optionTwo;
public SamplePage()
{
segControl = new SegmentedControl();
optionOne = new SegmentedControlOption();
optionTwo = new SegmentedControlOption();
optionOne.Text = "One";
optionTwo.Text = "Two";
segControl.Children.Add(optionOne);
segControl.Children.Add(optionTwo);
var stack = new StackLayout()
{
VerticalOptions = LayoutOptions.StartAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Children = { segControl }
};
this.Content = stack;
}
}
ScreenShot Attached
Just some suggestions and explanations.
We can't put a ContentPage inside another ContentPage
It's better to use ContentView instead of ContentPage
Grid is more recommended in this scenario , since it fills with the whole Screen.
Use ValueChanged event to change the view dynamically.
Code :
Page
public partial class SegmentedAppPage : ContentPage
{
SegmentedControl segControl;
SegmentedControlOption scOptionOne;
SegmentedControlOption scOptionTwo;
Grid grid;
View1 view1 = new View1();
View2 view2 = new View2();
public SegmentedAppPage()
{
InitializeComponent();
segControl = new SegmentedControl();
segControl.SelectedValue = "One";
scOptionOne = new SegmentedControlOption();
scOptionTwo = new SegmentedControlOption();
scOptionOne.Text = "One";
scOptionTwo.Text = "Two";
segControl.Children.Add(scOptionOne);
segControl.Children.Add(scOptionTwo);
grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.Children.Add(segControl, 0, 0);
grid.Children.Add(view1, 0, 1);
this.Content = grid;
segControl.ValueChanged += SegControl_ValueChanged;
}
private void SegControl_ValueChanged(object sender, EventArgs e)
{
SegmentedControl control = sender as SegmentedControl;
if(control.SelectedValue is "One")
{
grid.Children.Remove(view2);
grid.Children.Add(view1,0,1); //This line
}
else if (control.SelectedValue is "Two")
{
grid.Children.Remove(view1);
grid.Children.Add(view2, 0, 1); //This line
}
this.Content = grid;
}
}
ContentView
public class View1 : ContentView
{
public View1()
{
Content = new StackLayout
{
BackgroundColor = Color.Green,
Children = {
new Label { Text = "View1" }
}
};
}
}
To set default value on segmentedControl , modify code in SegmentedControlRenderers
protected override void OnElementChanged(ElementChangedEventArgs<SegmentedControl> e)
{
base.OnElementChanged(e);
var segmentedControl = new UISegmentedControl();
for (var i = 0; i < e.NewElement.Children.Count; i++)
{
segmentedControl.InsertSegment(e.NewElement.Children[i].Text, i, false);
}
segmentedControl.ValueChanged += (sender, eventArgs) => {
e.NewElement.SelectedValue = segmentedControl.TitleAt(segmentedControl.SelectedSegment);
};
segmentedControl.SelectedSegment = 0; // add this line
SetNativeControl(segmentedControl);
}
Test

Issue with FlowListView Xamarin.Forms

I am using FlowListView To set gallery view in my xamarin forms application, with following code..
public class Page1 : ContentPage
{
public Page1()
{
ObservableCollection<ItemModel> List = new ObservableCollection<ItemModel>();
string[] images = {
"https://farm9.staticflickr.com/8625/15806486058_7005d77438.jpg",
"https://farm5.staticflickr.com/4011/4308181244_5ac3f8239b.jpg",
"https://farm8.staticflickr.com/7423/8729135907_79599de8d8.jpg",
"https://farm3.staticflickr.com/2475/4058009019_ecf305f546.jpg",
"https://farm6.staticflickr.com/5117/14045101350_113edbe20b.jpg",
"https://farm2.staticflickr.com/1227/1116750115_b66dc3830e.jpg",
"https://farm8.staticflickr.com/7351/16355627795_204bf423e9.jpg",
"https://farm1.staticflickr.com/44/117598011_250aa8ffb1.jpg",
"https://farm8.staticflickr.com/7524/15620725287_3357e9db03.jpg",
"https://farm9.staticflickr.com/8351/8299022203_de0cb894b0.jpg",
};
int number = 0;
for (int n = 0; n < 20; n++)
{
for (int i = 0; i < images.Length; i++)
{
number++;
var item = new ItemModel()
{
ImageUrl = images[i],
FileName = string.Format("image_{0}.jpg", number),
};
List.Add(item);
}
}
FlowListView listView = new FlowListView()
{
FlowColumnTemplate = new DataTemplate(typeof(ListCell)),
SeparatorVisibility = SeparatorVisibility.None,
HasUnevenRows = true,
FlowColumnMinWidth = 110,
FlowItemsSource = List,
};
listView.FlowItemTapped += (s, e) =>
{
var item = (ItemModel)e.Item;
if (item != null)
{
App.Current.MainPage.DisplayAlert("Alert", "Tapped {0} =" + item.FileName, "Cancel");
}
};
Content = new StackLayout
{
Children = {
listView
}
};
}
}
public class ItemModel
{
public string ImageUrl { get; set; }
public string FileName { get; set; }
}
public class ListCell : View
{
public ListCell()
{
CachedImage IconImage = new CachedImage
{
HeightRequest = 100,
Aspect = Aspect.Fill,
DownsampleHeight = 100,
DownsampleUseDipUnits = false,
LoadingPlaceholder = "image_loading.png",
ErrorPlaceholder = "image_error.png"
};
IconImage.SetBinding(CachedImage.SourceProperty, "ImageUrl");
Label NameLabel = new Label
{
Opacity = 0.5,
HorizontalOptions = LayoutOptions.Fill,
HorizontalTextAlignment = TextAlignment.Center,
VerticalOptions = LayoutOptions.End,
};
NameLabel.SetBinding(Label.TextProperty, "FileName");
Grid grd = new Grid
{
Padding = 3,
ColumnDefinitions = {
new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star) },
},
RowDefinitions = {
new RowDefinition { Height=GridLength.Star},
},
};
grd.Children.Add(IconImage,0,0);
grd.Children.Add(NameLabel, 0, 1);
}
}
i added all the dependency of FlowListView, FFImage etc,
This above code just showing blank screen, Not displaying any data...
You're ListCell has nothing to show.
Append the existing lines to set the content to the grid in your custom ViewCell.
grd.Children.Add(IconImage,0,0);
grd.Children.Add(NameLabel, 0, 1);
Content = grd; <--- add this line
Also have you done the following as per advice from the author? i.e. You've added the nuget library to the platforms in addition to the PCL and added the corresponding initialisation code for the library?
You must add this line to your platform specific project (AppDelegate.cs, MainActivity.cs, etc) before you use FFImageLoading:
CachedImageRenderer.Init();
This is what I got in my IOS:
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
FFImageLoading.Forms.Touch.CachedImageRenderer.Init(); <---- this line
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
}

how to use swTableView in Xamarin IOS.

I am totally new to C# and starting with xamarin IOS code. i am basically from native app background.
i wanted simple app showing how to use swTableView controller in xamarin to show table as mention below.
Like :
ColumnNam ColumnNam ColumnNam ColumnNam
data1 data2 data3 data4
data5 data6 data7 data8
i tried search for the example but i did not find one...if any one already has information please let me know..
Thx in advance
There is no system control can perform effect like you need, you must customize one, I write a sample for you to reference:
In ViewController.cs:
public override void ViewDidLoad ()
{
this.Title = "testTalbeView";
this.View.Frame = UIScreen.MainScreen.Bounds;
this.View.BackgroundColor = UIColor.White;
UITableView tableView = new UITableView (UIScreen.MainScreen.Bounds);
tableView.SeparatorStyle = UITableViewCellSeparatorStyle.None;
tableView.Source = new MyTableSource ();
this.Add (tableView);
}
MyTableSource.cs:
public class MyTableSource : UITableViewSource
{
private string cellID = "MyCell";
private int columns = 2;
private List<string> dataList;
public MyTableSource ()
{
dataList = new List<string> ();
for (int i = 0; i < 10; i++) {
dataList.Add ("data " + i.ToString ());
}
}
#region implemented abstract members of UITableViewSource
public override nint RowsInSection (UITableView tableview, nint section)
{
return dataList.Count / columns + 1;
}
public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
{
MyCell cell = tableView.DequeueReusableCell (cellID) as MyCell;
if (null == cell) {
cell = new MyCell (UITableViewCellStyle.Default, cellID);
cell.TextLabel.TextAlignment = UITextAlignment.Center;
}
int row = (int)indexPath.Row;
if (0 == row) {
cell.SetData ("Column0", "Column1");
}
else{
cell.SetData (dataList [(row-1) * columns], dataList [(row-1) * columns + 1]);
}
return cell;
}
#endregion
}
MyCell.cs:
public class MyCell : UITableViewCell
{
private UILabel lbC0;
private UILabel lbC1;
public MyCell (UITableViewCellStyle style,string cellID):base(style,cellID)
{
lbC0 = new UILabel ();
lbC0.TextAlignment = UITextAlignment.Center;
this.AddSubview (lbC0);
lbC1 = new UILabel ();
lbC1.TextAlignment = UITextAlignment.Center;
this.AddSubview (lbC1);
}
public void SetData(string str0,string str1)
{
lbC0.Text = str0;
lbC1.Text = str1;
}
public override void LayoutSubviews ()
{
nfloat lbWidth = this.Bounds.Width / 2;
nfloat lbHeight = this.Bounds.Height;
lbC0.Frame = new CoreGraphics.CGRect (0, 0, lbWidth, lbHeight);
lbC1.Frame = new CoreGraphics.CGRect (lbWidth, 0, lbWidth, lbHeight);
}
}
Then you can get the tableView like the picture:
Hope it can help you.

Resources