How can I change the color or/and the background of UIAlertView. Found examples in objective-c, dunno how to apply them in monotouch
This should get you started, you probably need to tweak the image frame a bit to get it correct relative to your background image.
public class FooAlertView : UIAlertView
{
UIImageView imageView;
public FooAlertView()
{
this.Title = "Alert!";
this.Message = "Puppies are cute...";
AddButton("OK!");
imageView = new UIImageView(UIImage.FromFile("Images/popover/popoverBg.png"));
}
public override void Draw(RectangleF rect)
{
base.Draw(rect);
foreach(var uiview in this.Subviews) {
if(uiview.GetType() == typeof(UIImageView)) {
uiview.RemoveFromSuperview();
this.AddSubview(imageView);
this.SendSubviewToBack(imageView);
}
}
}
}
NO need to add new sub view with image. You can replace existing image in image view.
public override void Draw(RectangleF rect)
{
base.Draw(rect);
foreach (var uiview in this.Subviews)
{
if (uiview.GetType() == typeof(UIImageView))
{
UIImageView imageView = uiview as UIImageView;
if (imageView != null) imageView.Image = UIImage.FromFile("Images/header.png");
}
}
}
Related
I'm trying to use UICollectionView but I can't find any samples that I can take advantage of. I needed the UICollectionView by code (without using swift/storyboard/forms). Could you give me a really simple example? For example 2 lines with 2 columns please? Basic stuff just to try to understand how I can implement it.
Thank you
You can refer to Collection Views in Xamarin.iOS doc to check how to use Collection View with Code .And here I will show a sample code to explain how to implement it .
Could you give me a really simple example? For example 2 lines with 2 columns please?
First , need to create a GridLayout :
public class GridLayout : UICollectionViewFlowLayout
{
public GridLayout ()
{
}
public override bool ShouldInvalidateLayoutForBoundsChange (CGRect newBounds)
{
return true;
}
public override UICollectionViewLayoutAttributes LayoutAttributesForItem (NSIndexPath path)
{
return base.LayoutAttributesForItem (path);
}
public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect (CGRect rect)
{
return base.LayoutAttributesForElementsInRect (rect);
}
}
Then you can init the Collection View in ViewDidLoad :
static NSString animalCellId = new NSString("AnimalCell");
List<IAnimal> animals;
animals = new List<IAnimal>();
for (int i = 0; i < 2; i++)
{
animals.Add(new Monkey());
}
// Perform any additional setup after loading the view, typically from a nib.
UICollectionView collectionView = new UICollectionView(new CGRect(0, 0, UIScreen.MainScreen.Bounds.Size.Width, 300), new GridLayout());
collectionView.RegisterClassForCell(typeof(AnimalCell), animalCellId);
collectionView.BackgroundColor = UIColor.Blue;
collectionView.DataSource = new MyCollectionViewDataDelegate(animals);
View.AddSubview(collectionView);
Here you also need to creat a Custom Cell for your needs , this can be modified by yourself :
public class AnimalCell : UICollectionViewCell
{
UIImageView imageView;
[Export("initWithFrame:")]
public AnimalCell(CGRect frame) : base(frame)
{
BackgroundView = new UIView { BackgroundColor = UIColor.Orange };
SelectedBackgroundView = new UIView { BackgroundColor = UIColor.Green };
ContentView.Layer.BorderColor = UIColor.LightGray.CGColor;
ContentView.Layer.BorderWidth = 2.0f;
ContentView.BackgroundColor = UIColor.White;
ContentView.Transform = CGAffineTransform.MakeScale(0.8f, 0.8f);
imageView = new UIImageView(UIImage.FromBundle("placeholder.png"));
imageView.Center = ContentView.Center;
imageView.Transform = CGAffineTransform.MakeScale(0.7f, 0.7f);
ContentView.AddSubview(imageView);
}
public UIImage Image
{
set
{
imageView.Image = value;
}
}
[Export("custom")]
void Custom()
{
// Put all your custom menu behavior code here
Console.WriteLine("custom in the cell");
}
public override bool CanPerform(Selector action, NSObject withSender)
{
if (action == new Selector("custom"))
return true;
else
return false;
}
}
The MyCollectionViewDataDelegate also need to be created:
public class MyCollectionViewDataDelegate : UICollectionViewDataSource
{
private List animals;
public MyCollectionViewDataDelegate(List<IAnimal> animals)
{
this.animals = animals;
}
public override nint NumberOfSections(UICollectionView collectionView)
{
return 2;
}
public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
return animals.Count;
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var animalCell = (AnimalCell)collectionView.DequeueReusableCell(animalCellId, indexPath);
var animal = animals[indexPath.Row];
animalCell.Image = animal.Image;
return animalCell;
}
}
You can find that animalCell should be registed when init Collection View .
Then effect :
This is the sample link for reference .
I'm building an app in xamarin ios using AvPlayer. How can I hide the seek bar ?
_playerViewController = new CustomAVPlayerViewController();
_player = new AVPlayer();
_playerViewController.Player = _player;
SetNativeControl(_playerViewController.View);
public class CustomAVPlayerViewController: AVPlayerViewController
{
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
}
}
If you don't want to show the controls or want to highly customize the appearance, I recommend you to use AVPlayerLayer:
public class CustomPlayerRenderer : ViewRenderer<CustomPlayer, UIView>
{
AVPlayer _player;
AVPlayerLayer _playerLayer;
protected override void OnElementChanged(ElementChangedEventArgs<CustomPlayer1> e)
{
base.OnElementChanged(e);
if (Control == null)
{
_player = new AVPlayer(new NSUrl(NSBundle.MainBundle.PathForResource("sample.mp4", null), false));
_playerLayer = AVPlayerLayer.FromPlayer(_player);
UIView view = new UIView();
view.Layer.AddSublayer(_playerLayer);
SetNativeControl(view);
//_player.Play();
// Add custom controls as you want on this view
}
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
_playerLayer.Frame = rect;
}
}
I'm experiencing with the UICollectionView(Controller) for the first time. Actually it should be as simple as working with TableViews, it's not though.
Rather than showing all images in a flow (several rows) just the top row is displayed. All the other images are somewhere... scrolling is enabled but nothing happens, no bouncing, no scrolling, ...
And after an orientation change (and back) some more images are visible but they appear randomly. After every orientation change they appear at an other location.
My example should have 7 images.
My properties in IB:
First time:
After rotating (and back):
And my source code to implement the photo gallery.
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.Collections.Generic;
using Xamarin.Media;
using MonoTouch.AssetsLibrary;
using MonoTouch.CoreGraphics;
using System.Diagnostics;
using System.Linq;
using System.Drawing;
namespace B2.Device.iOS
{
public partial class TagesRapportDetailRegieBilderCollectionViewController : UICollectionViewController
{
private const string Album = "Rapport";
public TagesRapportDetailRegieBilderSource Source { get; private set; }
private TagesRapportDetailRegieBilderDelegate _delegate;
public TagesRapportDetailRegieBilderCollectionViewController (IntPtr handle) : base (handle)
{
Source = new TagesRapportDetailRegieBilderSource(this);
_delegate = new TagesRapportDetailRegieBilderDelegate(this);
// Delegate - Muss im konstruktor sein. ViewDidLoad geht nicht!
CollectionView.Delegate = _delegate;
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Cell Klasse registrieren
CollectionView.RegisterClassForCell (typeof(ImageCell), new NSString("imageCell"));
// DataSource
CollectionView.Source = Source;
// Bilder laden
LoadImages();
}
private void LoadImages()
{
Source.Images.Clear();
var assetsLibrary = new ALAssetsLibrary();
assetsLibrary.Enumerate(ALAssetsGroupType.Album, GroupsEnumeration, GroupsEnumerationFailure);
}
private void GroupsEnumeration(ALAssetsGroup group, ref bool stop)
{
if (group != null && group.Name == Album)
{
//notifies the library to keep retrieving groups
stop = false;
//set here what types of assets we want,
//photos, videos or both
group.SetAssetsFilter(ALAssetsFilter.AllPhotos);
//start the asset enumeration
//with ALAssetsGroup's Enumerate method
group.Enumerate(AssetsEnumeration);
CollectionView.ReloadData();
}
}
private void AssetsEnumeration(ALAsset asset, int index, ref bool stop)
{
if (asset != null)
{
//notifies the group to keep retrieving assets
stop = false;
//use the asset here
var image = new UIImage(asset.AspectRatioThumbnail());
Source.Images.Add(image);
}
}
private void GroupsEnumerationFailure(NSError error)
{
if (error != null)
{
new UIAlertView("Zugriff verweigert", error.LocalizedDescription, null, "Schliessen", null).Show();
}
}
}
public class TagesRapportDetailRegieBilderDelegate : UICollectionViewDelegateFlowLayout
{
private TagesRapportDetailRegieBilderCollectionViewController _controller;
public TagesRapportDetailRegieBilderDelegate(TagesRapportDetailRegieBilderCollectionViewController controller)
{
_controller = controller;
}
public override System.Drawing.SizeF GetSizeForItem(UICollectionView collectionView, UICollectionViewLayout layout, NSIndexPath indexPath)
{
var size = _controller.Source.Images[indexPath.Row].Size.Width > 0
? _controller.Source.Images[indexPath.Row].Size : new SizeF(100, 100);
size.Width /= 3;
size.Height /= 3;
return size;
}
public override UIEdgeInsets GetInsetForSection(UICollectionView collectionView, UICollectionViewLayout layout, int section)
{
return new UIEdgeInsets(50, 20, 50, 20);
}
}
public class TagesRapportDetailRegieBilderSource : UICollectionViewSource
{
private TagesRapportDetailRegieBilderCollectionViewController _controller;
public List<UIImage> Images { get; set; }
public TagesRapportDetailRegieBilderSource(TagesRapportDetailRegieBilderCollectionViewController controller)
{
_controller = controller;
Images = new List<UIImage>();
}
public override int NumberOfSections(UICollectionView collectionView)
{
return 1;
}
public override int GetItemsCount(UICollectionView collectionView, int section)
{
return Images.Count;
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var cell = collectionView.DequeueReusableCell(new NSString("imageCell"), indexPath) as ImageCell;
cell.Image = Images[indexPath.Row];
return cell;
}
}
public class ImageCell : UICollectionViewCell
{
UIImageView imageView;
[Export ("initWithFrame:")]
public ImageCell (System.Drawing.RectangleF frame) : base (frame)
{
imageView = new UIImageView(frame);
imageView.AutoresizingMask = ~UIViewAutoresizing.None;
ContentView.AddSubview (imageView);
}
public UIImage Image
{
set
{
imageView.Image = value;
}
}
}
}
If all you want to do is displaying the cells in an uniform grid, overriding GetSizeForItem shouldn't be necessary in the first place. Just configure the cellsize property of your flow layout either in IB or programatically during ViewDidLoad and be done with it.
There's another problem with your code:
group.Enumerate(AssetsEnumeration)
This will run asynchronously. That means:
CollectionView.ReloadData();
Will only cover a small subset of your images. It would be better to issue a ReloadData() when group == null, which indicates that the enumeration is complete.
You could also avoid ReloadData alltogether and call CollectionView.InsertItem() everytime you've added an image. This has the benefit of your items become immediately visible instead of all of them at once after everything has been enumerated - which may take some time (on the device). The downside is that you've got to be careful to not run into this.
I would like to draw a rectangle in every tablevievcell of my MvxTableViewController.
I have a custom cellLabel extending UIView
namespace Next.Client.Application.iOS.Views.UI
{
[Register("CellLabel")]
public class CellLabel : UIView
{
public CellLabel()
{
Initialize();
}
public CellLabel(RectangleF bounds)
: base(bounds)
{
Initialize();
}
void Initialize()
{
BackgroundColor = UIColor.Red;
}
public override void Draw(RectangleF rect)
{
base.Draw(rect);
//get graphics context
using (CGContext gc = UIGraphics.GetCurrentContext())
{
//set up drawing attributes
gc.SetLineWidth(1);
UIColor.Blue.SetFill();
UIColor.Red.SetStroke();
//create geometry
var path = new CGPath();
path.AddLines(new PointF[]{
new PointF (0, 45),
new PointF (80, 45),
new PointF (90, 50),
new PointF (0, 50)
});
path.CloseSubpath();
//add geometry to graphics context and draw it
gc.AddPath(path);
gc.DrawPath(CGPathDrawingMode.FillStroke);
}
}
}
}
and a custom cell where to draw in
namespace Next.Client.Application.iOS
{
public partial class ObservationCell : MvxTableViewCell
{
public static readonly UINib Nib = UINib.FromName ("ObservationCell", NSBundle.MainBundle);
public static readonly NSString Key = new NSString ("ObservationCell");
private CellLabel _labelView;
public ObservationCell (IntPtr handle) : base (handle)
{
_labelView = new CellLabel();
this.AddSubview(_labelView);
this.DelayBind(() => {
var set = this.CreateBindingSet<ObservationCell, Observation>();
set.Bind(MainLbl).To(observation => observation.BrutText);
set.Bind(SubLeftLbl).To(observation => observation.Praticien.Personne.DisplayFullName);
set.Bind(SubRightLbl).To(observation => observation.DateTimeHumanShort);
set.Apply();
});
}
public static ObservationCell Create ()
{
return (ObservationCell)Nib.Instantiate (null, null) [0];
}
}
}
but nothing show up :/
any ideas ?
Your CellLabel doesn't currently seem to have any Frame - so it's probably being drawn inside (0,0,0,0)
Try:
_labelView = new CellLabel(new RectangleF(0,0,320,100));
this.AddSubview(_labelView);
If you add a CellLabel(IntPtr) constructor, then you can also use the CellLabel as a type in the XIB editor - it won't fully draw within the editor, but the editor will allow you to specify it as the type and it will get correctly loaded at runtime.
One final note... I don't think I'd call it a Label - could be confusing to people who read the code later.
I am in need of some help from you guys. I have a Monotouch UITableView which contains some web images. I have implemented a Task to fetch them asynchronously so the UI is responsive, an even added some animations to fade them in when they are fetched from the web.
My problems start when the user scrolls down very fast down the UITableView, so since the cells are resusable, several background tasks are queued for images. When he is at the bottom of the list, he might see the thumbnail displaying an image for another cell, then another, then another, then another, as the tasks are completed and each image replaces the other one. I am in need of some sort of checking whether the currently displayed cell corresponds to the correct image url, but not sure how to do that.
Here is the code for my TableSource class.
using System;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
{
public class ListDelegate:UITableViewDelegate
{
private UINavigationController nav;
public override float GetHeightForRow (UITableView tableView, NSIndexPath indexPath)
{
return 128;
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
DealViewController c = new DealViewController(((ListDataSource)tableView.DataSource).deals[indexPath.Row].Id,nav);
nav.PushViewController(c,true);
tableView.DeselectRow(indexPath,true);
}
public ListDelegate(UINavigationController nav)
{
this.nav = nav;
}
}
public class ListDataSource:UITableViewDataSource
{
bool toggle=true;
Dictionary<string,UIImage> images = new Dictionary<string, UIImage>();
public List<MyDeal> deals = new List<MyDeal>();
Dictionary<int,ListCellViewController> controllers = new Dictionary<int, ListCellViewController>();
public ListDataSource(List<MyDeal> deals)
{
this.deals = deals;
}
public override int RowsInSection (UITableView tableview, int section)
{
return deals.Count;
}
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell("cell");
ListCellViewController cellController = null;
if (cell == null || !controllers.ContainsKey(cell.Tag))
{
cellController = new ListCellViewController();
NSBundle.MainBundle.LoadNib("ListCellViewController", cellController, null);
cell = cellController.Cell;
cell.Tag = Environment.TickCount;
controllers.Add(cell.Tag, cellController);
}
else
{
cellController = controllers[cell.Tag];
}
if (toggle)
{
cell.BackgroundView = new UIImageView(UIImage.FromFile("images/bg1.jpg"));
}
else
{
cell.BackgroundView = new UIImageView(UIImage.FromFile("images/bg2.jpg"));
}
toggle = !toggle;
MyDeal d = deals[indexPath.Row];
cellController.SetValues(d.Title,d.Price,d.Value,d.DiscountPercent);
GetImage(cellController.Thumbnail,d.Thumbnail);
return cell;
}
private void GetImage(UIImageView img, string url)
{
img.Alpha = 0;
if (url != string.Empty)
{
if (images.ContainsKey(url))
{
img.Image = images[url];
img.Alpha = 1;
}
else
{
var context = TaskScheduler.FromCurrentSynchronizationContext ();
Task.Factory.StartNew (() => {
NSData imageData = NSData.FromUrl(new NSUrl(url));
var uimg = UIImage.LoadFromData(imageData);
images.Add(url,uimg);
return uimg;
}).ContinueWith (t => {
InvokeOnMainThread(()=>{
img.Image = t.Result;
RefreshImage(img);
});
}, context);
}
}
}
private void RefreshImage(UIImageView img)
{
UIView.BeginAnimations("imageThumbnailTransitionIn");
UIView.SetAnimationDuration(0.5f);
img.Alpha = 1.0f;
UIView.CommitAnimations();
}
}
}
Here is the ListCellViewController, that contains a custom cell
using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
{
public partial class ListCellViewController : UIViewController
{
#region Constructors
// The IntPtr and initWithCoder constructors are required for items that need
// to be able to be created from a xib rather than from managed code
public ListCellViewController (IntPtr handle) : base(handle)
{
Initialize ();
}
[Export("initWithCoder:")]
public ListCellViewController (NSCoder coder) : base(coder)
{
Initialize ();
}
public ListCellViewController () : base("ListCellViewController", null)
{
Initialize ();
}
void Initialize ()
{
}
public UIImageView Thumbnail
{
get{return thumbnailView;}
}
public UITableViewCell Cell
{
get {return cell;}
}
public void SetValues(string title,decimal price,decimal valuex,decimal discount,int purchases)
{
}
#endregion
}
}
All help is greatly appreciated
I have found a simple (maybe not optimal) solution. The trick I used is a Queue object to store the last n valid image urls, where n the number of words displayable in the screen. Once a cell is reused, the last image url is dequeued and when it is about to be displayed I check if it's in the queue, and if it's not I reject it.