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;
}
}
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've tried all permutations I can find on the web and just can't seem to get this to work.
I have my iOS app UI defined within a storyboard and the MVVM framework is mostly MVVMCross with some sprinkling of ReactiveUI thrown in for flavor.
I have a RootViewController defined where I generate the SideBarController that is attached to the AppDelegate as so:
[Register ("AppDelegate")]
public partial class AppDelegate : MvxApplicationDelegate
{
public override UIWindow Window {
get;
set;
}
public AppDelegate ()
{
}
public SidebarController SidebarController { get; set; }
public override void FinishedLaunching (UIApplication application)
{
var presenter = new MvxModalSupportTouchViewPresenter (this, Window);
var setup = new Setup (this, presenter);
setup.Initialize ();
var startUp = Mvx.Resolve<IMvxAppStart> ();
startUp.Start ();
}
}
And in the RootViewController I have:
public override void ViewDidLoad()
{
base.ViewDidLoad();
if (ViewModel == null)
return;
var appDelegate = UIApplication.SharedApplication.Delegate as AppDelegate;
appDelegate.SidebarController = new SidebarController (this,
(UIViewController)this.CreateViewControllerFor<LoginViewModel>(),
(UIViewController)this.CreateViewControllerFor<SideMenuViewModel>());
appDelegate.SidebarController.MenuWidth = 250;
appDelegate.SidebarController.ReopenOnRotate = false;
appDelegate.SidebarController.MenuLocation = SidebarController.MenuLocations.Right;
}
After the user has a successful login they are then navigated to a landing page that has a burger button on it. Once the user clicks the burger button the side menu isn't show but all tracing before and after the ToggleMenu() call gets executed. I'm racking my brain trying to get this to work but after 3 days I think I may have given myself a concussion.
Has anyone tried to get this combo working?
For me it is working. I am not exactly sure where your problems is, but this is my code:
[Register ("AppDelegate")]
public partial class AppDelegate : MvxApplicationDelegate
{
UIWindow window;
public RootViewController RootViewController { get { return window.RootViewController as RootViewController; } }
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
window = new UIWindow(UIScreen.MainScreen.Bounds);
var presenter = new Presenter(this, window);
var setup = new Setup(this, presenter);
setup.Initialize();
var startup = Mvx.Resolve<IMvxAppStart>();
startup.Start();
window.MakeKeyAndVisible();
return true;
}
}
And for the rootcontroller:
public class RootViewController: UIViewController, IMvxCanCreateTouchView
{
public SidebarController SidebarController { get; private set; }
private UIViewController root;
public RootViewController (UIViewController root)
{
this.root = root;
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
var menuContentView = this.CreateViewControllerFor<MenuViewModel> () as MenuViewController;
SidebarController = new SidebarController (this, root, menuContentView) {
MenuLocation = SidebarController.MenuLocations.Left,
HasShadowing = false
};
}
public void NavigateToView (UIViewController view)
{
SidebarController.ChangeContentView (new UINavigationController (view));
}
}
As a Base class for my other controllers i have this:
public interface IControllerWithCustomNavigation
{
void NavigateToView (UIViewController controller);
}
public class BaseController<TViewModel>: MvxViewController where TViewModel: BaseViewModel
{
protected bool NavigationBarEnabled = true;
public new TViewModel ViewModel {
get { return (TViewModel)base.ViewModel; }
set { base.ViewModel = value; }
}
public BaseController (string nib) : base (nib, null)
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
if (NavigationBarEnabled) {
NavigationController.NavigationBarHidden = false;
updateNavigationBar ();
if (isRootViewModel()) {
addNavigationBarItemForMenu ();
}
} else if (NavigationController != null) {
NavigationController.NavigationBarHidden = true;
}
}
private void updateNavigationBar()
{
var navigationBar = NavigationController.NavigationBar;
var colorTint = UIColor.FromRGB (133, 231, 110);
var colorWhite = UIColor.White;
navigationBar.BarTintColor = colorWhite;
navigationBar.TintColor = colorTint;
navigationBar.SetTitleTextAttributes (new UITextAttributes {
TextColor = UIColor.FromRGB (13, 19, 26)
});
}
private bool isRootViewModel()
{
return NavigationController.ViewControllers.Length < 2; // Every view, even the RootView, is counted here.
}
private void addNavigationBarItemForMenu()
{
var sidebarButton = new UIBarButtonItem (
UIImage.FromFile ("menu_icon.png"),
UIBarButtonItemStyle.Plain,
(object sender, EventArgs e) => {
(UIApplication.SharedApplication.Delegate as AppDelegate).RootViewController.SidebarController.ToggleMenu();
}
);
NavigationItem.SetLeftBarButtonItem (sidebarButton, true);
}
public virtual void NavigateToView (UIViewController controller)
{
(UIApplication.SharedApplication.Delegate as AppDelegate).RootViewController.NavigateToView (controller);
}
}
So after looking over the code that Martijn posted and then actually doing some snooping through his previous posts, I decided that it would be best to create my own MvxViewPresenter and so far it works.
public class SideBarControllerTouchViewPresenter : MvxModalSupportTouchViewPresenter
{
private UIWindow _window;
public SidebarController SidebarController {
get ;
set ;
}
public UIViewController RootController {
get;
private set;
}
public SideBarControllerTouchViewPresenter (UIApplicationDelegate applicationDelegate, UIWindow window)
: base(applicationDelegate, window)
{
_window = window;
}
public override void ChangePresentation (Cirrious.MvvmCross.ViewModels.MvxPresentationHint hint)
{
base.ChangePresentation (hint);
}
protected override void ShowFirstView (UIViewController viewController)
{
base.ShowFirstView (viewController);
}
protected override UINavigationController CreateNavigationController (UIViewController viewController)
{
var navController = new UINavigationController (viewController);
var menuController = UIStoryboard.FromName ("storyboard", null).InstantiateViewController ("MenuTableViewController") as MenuTableViewController;
RootController = new UIViewController ();
SidebarController = new SidebarController (this.RootController, navController, menuController);
return navController;
}
protected override void SetWindowRootViewController (UIViewController controller)
{
_window.AddSubview (RootController.View);
_window.RootViewController = RootController;
}
}
So thanks for getting me the rest of the way there.
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 use Monotouch.Dialog (Xamarin.iOS Version: 6.2.0.65) to create a RadioGroup with RadioElements. I only want the 'search' functionality in the second screen (where the user selects from the long list), so i created a separate DialogViewController where i enabled the search filter (enableSearch = true).
When typing in the search box, the app crashes in the GetCell method of the RadioElement.
"Object reference not set to an instance of an object" on line 1064 of Element.cs. Do i have GC problems? I managed to simulate it in a small app... Don't pay attention some weird field members, thats me testing if i'm begin GC...
using MonoTouch.Dialog;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace SearchCrash
{
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to
// application events from iOS.
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
// class-level declarations
UIWindow window;
public UINavigationController NavigationController { get; set; }
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window = new UIWindow(UIScreen.MainScreen.Bounds);
this.NavigationController = new UINavigationController();
this.NavigationController.PushViewController(new FirstViewController(this.NavigationController), true);
window.RootViewController = this.NavigationController;
window.MakeKeyAndVisible();
return true;
}
}
public class FirstViewController : DialogViewController
{
private UINavigationController controller;
private LocatiesRootElement locRootElement;
private RadioGroup radioGroup;
public FirstViewController(UINavigationController c) : base(new RootElement("Test"), true)
{
this.controller = c;
}
public override void ViewDidLoad()
{
Section section = new Section();
radioGroup = new RadioGroup(0);
locRootElement = new LocatiesRootElement("test", radioGroup, this.controller);
section.Add(locRootElement);
Root.Add(section);
}
}
public class LocatiesRootElement : RootElement
{
private UINavigationController navigationController;
private LocatiesViewController locatiesViewController;
public LocatiesRootElement(string selectedLocatie, RadioGroup group, UINavigationController controller) : base("Locatie", group)
{
this.navigationController = controller;
this.locatiesViewController = new LocatiesViewController(this);
}
public override void Selected(DialogViewController dvc, UITableView tableView, NSIndexPath path)
{
this.navigationController.PushViewController(this.locatiesViewController, true);
}
}
public class LocatiesViewController : DialogViewController
{
public LocatiesViewController(LocatiesRootElement root) : base(root, true)
{
this.EnableSearch = true;
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Section sectionList = new Section();
RadioElement radioElement1 = new RadioElement("item 1");
RadioElement radioElement2 = new RadioElement("item 2");
sectionList.Add(radioElement1);
sectionList.Add(radioElement2);
Root.Add(sectionList);
}
}
}
Try enabling the search after you instantiate the DialogViewController.
Like this :
public LocatiesRootElement(string selectedLocatie, RadioGroup group, UINavigationController controller) : base("Locatie", group)
{
this.navigationController = controller;
this.locatiesViewController = new LocatiesViewController(this);
this.locatiesViewController.EnableSearch = true;
}
Hopefully that will work for you.
The bug report here includes a workaround for the root cause of the issue you're experiencing, but also talks about how filtering will then cause a usability issue of marking the nth element as selected even after a filter has been applied.
https://github.com/migueldeicaza/MonoTouch.Dialog/issues/203
If you don't want to update the core MTD code, you could use that same technique by putting it in your own UIBarSearchDelegate. Unfortunately, the default SearchDelegate class is internal, so you'll need to add all of the code in your delegate. I was able to do this and get it working without changing the MTD source:
public override void LoadView()
{
base.LoadView();
((UISearchBar)TableView.TableHeaderView).Delegate = new MySearchBarDelegate(this);
}
And then you use this instead of the base method:
public override void TextChanged (UISearchBar searchBar, string searchText)
{
container.PerformFilter (searchText ?? "");
foreach (var s in container.Root)
s.Parent = container.Root;
}
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");
}
}
}