iCarousel in Sprite Kit
You can use NSNotifications to show your character picker. You just need to observe the notifications posted by your SKScene
. Your viewDidLoad
should look something like:
override func viewDidLoad(){
super.viewDidLoad()
carousel.type = .CoverFlow
carousel.reloadData()
let spriteKitView = SKView()
spriteKitView.frame = self.view.bounds
self.view.insertSubview(spriteKitView, belowSubview: self.carousel)
spriteKitView.showsFPS = true
spriteKitView.showsNodeCount = true
spriteKitView.ignoresSiblingOrder = true
self.gameScene = GameScene(size:self.view.bounds.size)
self.gameScene.scaleMode = .AspectFill
self.gameScene.imageName = self.images[0] as! String
self.carousel.hidden = true
spriteKitView.presentScene(self.gameScene)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.showCarousel), name: gameScene.kShowNotification, object: nil)
}
You'll want to implementing carousel(carousel:iCarousel, didSelectItemAtIndex index:NSInteger)
so you know what is selected, and so you can return to game play. For example:
func carousel(carousel:iCarousel, didSelectItemAtIndex index:NSInteger)
{
self.gameScene.imageName = self.images[index] as! String
self.hideCarousel()
}
You also need to remove observing before your view controller is deallocated.
deinit
{
NSNotificationCenter.defaultCenter().removeObserver(self)
}
Your SKScene
can then post a notifications:
import SpriteKit
class GameScene: SKScene {
var imageName = "square1"{
didSet{
self.hidden = false
self.childNode.texture = SKTexture(imageNamed: imageName)
}
}
let kShowNotification = "showPicker"
var childNode = SKSpriteNode()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
self.childNode = SKSpriteNode(imageNamed: imageName)
self.childNode.anchorPoint = CGPointZero
self.childNode.position = CGPointZero
self.addChild(self.childNode)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.showCharPicker()
}
func showCharPicker()
{
self.hidden = true
NSNotificationCenter.defaultCenter().postNotificationName(kShowNotification, object: nil)
}
}
If you want to change hit detection, you need to subclass the view for which you need it to change. This case your iCarousel
view.
You can then either override hitTest
or pointInside
. I've created an iCarousel
subclass and overrode pointInside
to only return true when the point is inside one of the carousel's contentView
's subviews.
class CarouselSubclass: iCarousel {
override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
var inside = false
for view in self.contentView.subviews
{
inside = CGRectContainsPoint(view.frame, point)
if inside
{
return inside
}
}
return inside
}
}
You need to remember to change the class of your carousel in interface builder and update your outlet as well.
iCarousel on Game Swift+SpriteKit not working properly
You're not setting the frame of the carousel or setting constraints on it.
Try changing your setupCarousel
method to:
func setupCarousel() {
carousel = iCarousel()
carousel.dataSource = self
carousel.delegate = self
carousel.type = .Linear
carousel.reloadData()
// turn off autoresizing mask
carousel.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(self.carousel)
// Add constraints
carousel.topAnchor.constraintEqualToAnchor(self.topLayoutGuide.bottomAnchor).active = true
carousel.leadingAnchor.constraintEqualToAnchor(self.view.leadingAnchor).active = true
carousel.trailingAnchor.constraintEqualToAnchor(self.view.trailingAnchor).active = true
carousel.bottomAnchor.constraintEqualToAnchor(self.view.bottomAnchor).active = true
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.showCarousel), name: "showBallPicker", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.hideCarousel), name: "hideBallPicker", object: nil)
}
Update
These constraints will pin the carousel to the edges of your view controller's view. If you want to position it differently, you could, for example, replace those constraints with something like:
carousel.centerXAnchor.constraintEqualToAnchor(self.view.centerXAnchor).active = true
carousel.centerYAnchor.constraintEqualToAnchor(self.view.centerYAnchor, constant: -100).active = true
carousel.widthAnchor.constraintEqualToAnchor(self.view.widthAnchor).active = true
carousel.heightAnchor.constraintEqualToConstant(200.0).active = true
This will center the carousel horizontally and place the carousel 100 points up from the center vertically. The carousel will be the same width as it's superview but will always be 200 points tall. You can look at Apple's documentation for more options for using anchors to create constraints.
If you want to add labels to your carousel items you should do that in viewForItemAtIndex
. You can create a simple UIView
subclass that will hold a UIImageView
and UILabel
and return that instead of just a UIImageView
. For example:
class CarouselItem: UIView {
let imageView:UIImageView =
{
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .ScaleAspectFill
return imageView
}()
let label:UILabel =
{
let label = UILabel()
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.5
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .Center
label.numberOfLines = 0
return label
}()
override init(frame: CGRect)
{
super.init(frame: frame)
self.commonInit()
}
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
self.commonInit()
}
func commonInit()
{
self.addSubview(self.imageView)
self.addSubview(self.label)
self.imageView.topAnchor.constraintEqualToAnchor(self.topAnchor).active = true
self.imageView.centerXAnchor.constraintEqualToAnchor(self.centerXAnchor).active = true
self.imageView.widthAnchor.constraintEqualToAnchor(self.widthAnchor).active = true
self.imageView.heightAnchor.constraintEqualToAnchor(self.heightAnchor, multiplier: 0.9).active = true
self.label.topAnchor.constraintEqualToAnchor(self.imageView.bottomAnchor, constant: 8.0).active = true
self.label.centerXAnchor.constraintEqualToAnchor(self.centerXAnchor).active = true
}
}
Now in viewForItemAtIndex
func carousel(carousel: iCarousel, viewForItemAtIndex index: Int, reusingView view: UIView?) -> UIView {
var carouselItem: CarouselItem!
if view == nil {
carouselItem = CarouselItem(frame: CGRectMake(0, 0, 250, 250))
carouselItem.backgroundColor = UIColor.redColor()
}else{
carouselItem = view as! CarouselItem
}
carouselItem.imageView.image = UIImage(named: "\(imageArray.objectAtIndex(index))")
carouselItem.label.text = "Some Text"
return carouselItem
}
carouselCurrentItemIndexDidChange on iCarousel only being called when I swipe
You should set up your carousel views in viewForItemAtIndex: reusingView:
. The view returned by this method should represent the current state of that carousel item; so locked or "Select" as appropriate.
If the state of an item changes then you can call reloadItemAtIndex:
to have iCarousel request an updated view for that item by calling viewForItemAtIndex: reusingView:
.
You can scroll the carousel to a particular item by calling scrollToItemAtIndex:animated:
is it possible to implement iCarousel with SKScene array?
It's a little expensive in term of storage capacity, but it works perfectly.
Here's what you'll get:
When you click load arena, you'll get the following view to select your arena:
You have to select the arena and the click on the green button to return back to the calling view with the chosen arena loaded.
and here's the way to achieve it:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//UITableViewCell *cell=[tableView cellForRowAtIndexPath:indexPath];
selectedItem=[_Title objectAtIndex:indexPath.row];
[singleton setChoice:selectedItem];
tableSelectedItemIndexPath=indexPath; //Here we strore the selected item index so later when returninng to normal mode we can deselect the item
TableViewRef=tableView;
if([selectedItem isEqualToString:@"load arena])
{
if ([[SpriteMyScene getMapsVector] count] == 0){
UIAlertView * alert =[[UIAlertView alloc ] initWithTitle:@"Absence de carte à visualiser" message:@"Il n'y a pas de carte disponible" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
[alert show];
}
else{
[[[[self.tabBarController tabBar]items]objectAtIndex:2]setEnabled:TRUE];
[self.tabBarController setSelectedIndex:2 ];
}
}
if([selectedItem isEqualToString:@"save arena"])
{
UIAlertView * alert =[[UIAlertView alloc ] initWithTitle:@"XML Save" message:@"Enter the name of the file you wish to save." delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles: nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert addButtonWithTitle:@"OK"];
[alert show];
//We programmarically remove the selection
[TableViewRef deselectRowAtIndexPath:tableSelectedItemIndexPath animated:YES];
}
if([selectedItem isEqualToString:@"delete arena"])
{
int yCoordinate=40;
//This is the scroll pan ein which the xml file list is displayed
_polygonView = [[UIScrollView alloc] initWithFrame: CGRectMake ( 0, 0, 500, 300)];
_polygonView.backgroundColor=[UIColor clearColor];
[_polygonView setScrollEnabled:YES]; //we activated the scroll function
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //here we all directory paths on ios
NSString *docDir;
docDir=[paths objectAtIndex:0]; //this is the path to Document directory
//we get an array containing all files in a given directory. This is same as File class in java
NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docDir error:NULL];
for (int i = 0; i < (int)[directoryContent count]; i++)
{
NSRange range;
range=[[directoryContent objectAtIndex:i] rangeOfString:@".xml"];
if(range.location != NSNotFound)
{
//this index is used ot exlude the .xml part when displaying teh name sof the files to the user
int ToIndex=[[directoryContent objectAtIndex:i] length];
ToIndex-=4;
NSString *btnTitle=[[directoryContent objectAtIndex:i] substringToIndex:ToIndex];
if(![btnTitle isEqualToString:@"imageData"])
{
UIButton *FileButton = [[UIButton alloc] initWithFrame:CGRectMake(165, yCoordinate, 200, 40)];
[FileButton setTitle:btnTitle forState:UIControlStateNormal];
[FileButton setTitleColor:[UIColor whiteColor]forState:UIControlStateNormal];
[FileButton setEnabled:YES];
[FileButton setUserInteractionEnabled:YES];
[FileButton addTarget: self action: @selector(buttonIsPressed:) forControlEvents: UIControlEventTouchDown];
[FileButton setBackgroundColor:[UIColor blueColor]];
[_polygonView addSubview:FileButton];
yCoordinate+=45;
}
}
}
_polygonView.contentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height *2.5);
//This is the licensed class that is used to create a window pane
CustomIOS7AlertView* alertView=[[CustomIOS7AlertView alloc]init];
alertView.tag=1;
[alertView setFrame:CGRectMake(500, 0, 500, 500)];
[alertView setContainerView:_polygonView];
[alertView setButtonTitles:[NSMutableArray arrayWithObjects:@"Delete File", @"Cancel", nil]];
[alertView setDelegate:self];
[alertView show];
}
....
/*
* This method is used ot read the user input text value when user enters the name of the xml file
* This is used when saving a xml file
*/
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{ if (buttonIndex == 1) {
UITextField* fileName = [alertView textFieldAtIndex:0];
XMLHandler* xml=[[XMLHandler alloc] init];
[xml setXmlFileName:fileName.text];
[[SpriteViewController getSceneRef] snapShotScene:fileName.text];
//we save the image file
[xml generateImageFile:[SpriteMyScene getImageData]:[SpriteMyScene getImageFileName]];
//this function gets the _nodeDictionnary as argument
NSMutableDictionary* tmp = [singleton getSceneNodeDictionnary];
[xml generateXML:tmp];
}}
and the picture are taken each time the user save an arena using this method:
- (void) snapShotScene: (NSString*) imageName{
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.50);
[self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES];
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
@autoreleasepool
{
//convert image into .png format.
imageData = UIImagePNGRepresentation(image);
imageFileName= imageName;
[mapsVector addObject: imageData];
[fileNamesVector addObject: imageFileName];
}
}
For the iCarousel class, use this link: The iCarousel repository
I hope this will help.
Related Topics
Rotate a Imageview Around a Pivot Point in iOS
Uiview Rounded Corner - Swift 2.0
Hidden Property Cannot Be Changed Within an Animation Block
Code Coverage Result Is Not Accurate to Real Coverage in Xcode 7
Saving Audio After Effect in iOS
Swift 3 Imessage Extension Doesn't Open Url
Get Index of Object from Array of Dictionary with Key Value
Passing Data Between View Controllers Without Segue
How to Add .Plist File to All Targets in Xcode
Swift How to "Pass by Value" of a Object
Masked Uivisualeffectview Does Not Work on iOS 10
How to Hide API Keys in Github for iOS (Swift) Projects
What's Happening Behind the Scenes in Xctest's @Testable
iOS 10 Issue: Uiscrollview Not Scrolling, Even When Contentsize Is Set
Navigation with Only Back Button and Transparent Background
Swift - Convert Values in Array to Doubles or Floats