I am trying to get screen capture working on my iOS SpriteKit game using this code (by Aroth)
Basically I need to replace the SKView of my UIViewController with my own ScreenCaptureView (see the link). I changed the ScreenCaptureView in the example to derive from SKView instead of UIView.
I override loadView function in my game UIViewController class:
- (void)loadView
{
ScreenCaptureView *newView = [[ScreenCaptureView alloc] init];
newView.frame = CGRectMake(0, 0, 568, 320);//hard code for now
newView.clipsToBounds = NO;
self.view = newView;
[newView setNeedsDisplay];
NSLog(#"loadView %x", (int)newView);
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"viewDidLoad view %x %f x %f", (int)self.view ,self.view.frame.size.width, self.view.frame.size.height);
But its not working. The drawRect in ScreenCaptureView never gets called.
Any help is really appreciated.
Related
I've built an UIView in storyboard that is composed like this:
UIView (called _view)
UIVisualEffetView (dark)
UIVIew
Button
I've done like this for the ability to reuse it between several Navigation Controller. So for this I've set everything and I can show my view in my main controller called "ViewController" that is embedded in a navigation controller. But the issue is that the blur is opaque, for example the blue navigation bar of my view controller is not visible under the UIVIsualAffectView !
Here is the code I use for setting up the custom view :
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
_view.backgroundColor = [UIColor clearColor];
UIView *rootView = [[[NSBundle mainBundle] loadNibNamed:#"SideMenuView" owner:self options:nil] objectAtIndex:0];
CGRect newFrame = rootView.frame;
newFrame.size.width = [[UIScreen mainScreen] bounds].size.width / 2;
newFrame.size.height = [[UIScreen mainScreen] bounds].size.height;
[rootView setFrame:newFrame];
UIWindow* currentWindow = [UIApplication sharedApplication].keyWindow;
currentWindow.backgroundColor = [UIColor clearColor];
currentWindow.windowLevel = UIWindowLevelNormal;
[currentWindow addSubview:rootView];
}
And here is the code I use to call the view from my main controller:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.leftBarButton setTarget:self];
[self.leftBarButton setAction: #selector(test)];
}
- (void)test {
SideMenuView *test = [[SideMenuView alloc] init];
[self.view addSubview:test];
test.translatesAutoresizingMaskIntoConstraints = NO;
}
I've also tried to force the property "setOpaque" to No in my SideMenuView.m but without effect
Here is a screenshot of what it do:
Do you know guys what is wrong with my code ?
I've also added a button in the middle of the screen with a blue background but it's not visible under the blur so the issue is not navigation bar specific
Thanks in advance for your help !
I've resolved my issue by simply creating an UIView with clear background.
What I do for adding the blur effect is to create the UIVisualEffectView programmatically (doing this way it work perfectly !).
After that I'm adding my UIView as a subview of my UIVisualEffectView and voila :)
I am trying to do something like this -
- (void)viewDidLoad {
[super viewDidLoad];
ThingViewController *thingViewController = [self thingControllerForCard:self.card];
thingViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
UIView *view = [thingViewController view];
[self.view addSubview:view];
}
It just gives me a white screen with nothing in it. If I push the new view controller on the navigation stack it shows the controller properly. Any idea what I might be missing?
You should set the thingViewController frame on the viewDidLayoutSubviews.
viewDidLoad does not has the frames set correctly at this time:
- (void)viewDidLoad {
[super viewDidLoad];
ThingViewController *thingViewController = [self thingControllerForCard:self.card];
UIView *view = [thingViewController view];
[self.view addSubview:view];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
thingViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
I used the code below to present vViewController1
#property (retain,nonatomic) ViewController1 *vViewController1;
...
push vViewController1 from rootViewController
[self.navigationController pushViewController:vViewController1 animated:NO];
Viewcontroller1's viewWillAppear
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
CGRect frame = CGRectMake(0, 20, 320, 480);
self.view.frame = frame; ///aaa
NSLog(#"%f:%f:%f:%f",
frame.origin.x,frame.origin.y,frame.size.width,frame.size.height);
}
it outputs
0.000000:20.000000:320.000000:480.000000
but the view y position is always at
0
rather than
20
it looks like it is always
CGRectMake(0, 0, 320, 480);
and
self.view.frame = frame; ///aaa
can not relocate the position of the view.
I have try to set the position using code when call pushViewController,
but there is no way to make it work correctly.
Just wonder if it is a bug for pushViewController
Your comment welcome
I think you have autolayout turned on. So you need to override viewDidLayoutSubviews method like this:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.view.frame = CGRectMake(0, 0, 320, 480);
NSLog(#"%#", NSStringFromCGRect(self.view.frame));
}
And it's better to use NSStringFromCGRect for NSLog, rather creating 4 outputs doubles.
I read two questions here about that, both with the same answer. The suggested solution was to create the UIScrollView object, and then add it to the parent view of the SKScene in the target scene's didMoveToView:, removing it in willMoveFromView:.
And that is the target scene code I implemented:
#interface MQSSMakerScene ()
#property BOOL contentCreated;
#property MQSSMakerWorkspaceLayer *workspaceLayer;
#property MQSSMakerDockLayer *dockLayer;
#property UIScrollView *scrollView;
#end
#implementation MQSSMakerScene
- (id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size]) {
CGSize layerSize = CGSizeMake(944, 140);
CGPoint layerPosition = CGPointMake(40, 768-(140+30));
CGRect viewFrame = CGRectMake(layerPosition.x, layerPosition.y, layerSize.width, layerSize.height);
_scrollView = [[UIScrollView alloc] initWithFrame:viewFrame];
_scrollView.contentSize = CGSizeMake(2000, 120);
_scrollView.scrollEnabled = YES;
_scrollView.showsHorizontalScrollIndicator = YES;
_scrollView.backgroundColor = [UIColor brownColor];
}
return self;
}
- (void)didMoveToView:(SKView *)view
{
[super didMoveToView:view];
if(!self.contentCreated) {
[self createSceneContents];
self.contentCreated = YES;
}
[self.view addSubview:_scrollView]; // --> WHERE IT'S BEING ADDED
}
- (void)willMoveFromView:(SKView *)view
{
[super willMoveFromView:view];
[_scrollView removeFromSuperview]; // --> WHERE IT'S BEING REMOVED
}
- (void)createSceneContents
{
self.backgroundColor = [UIColor colorWithHue:.237 saturation:.56 brightness:.46 alpha:1];
self.scaleMode = SKSceneScaleModeAspectFill;
[self addChild:[self newMakerLayout]];
}
- (SKNode *)newMakerLayout
{
SKNode *mainLayout = [[SKNode alloc] init];
self.workspaceLayer = [[MQSSMakerWorkspaceLayer alloc] init];
self.dockLayer = [[MQSSMakerDockLayer alloc] init];
[mainLayout addChild:self.workspaceLayer];
[mainLayout addChild:self.dockLayer];
MQSSStoryObject *ob1 = [[MQSSStoryObject alloc] initWithImageNamed:#"maker-1.png"];
[self.workspaceLayer addChild:ob1];
return mainLayout;
}
#end
Please note that the user should go to this scene from the home scene when clicking on a button. The problem now is that once I add the line:
[self.view addSubview:_scrollView];
to add the UIScrollView object to this scene, the application no more goes to this scene and instead add the UIScrollView to the home scene I am transitioning from. It also doesn't remove it when transitioning to another scene. Once I comment out this line, everything works just as expected, clearly without presenting the UIScrollView.
I am stuck. Any help or advice is highly appreciated. Thanks!
I finally figured out what the problem was for me. I was using the -(void)willLayoutSubviews method of the viewController to ensure I had the correct bounds, but I had forgotten to see if my SKScene was already presented. That resulted in a new welcomeScene being presented each time the view was laid out on top of the old one.
-(void)willLayoutSubviews
{
if(!self.didPresentScene)
{
// Present scene here
....
self.didPresentScene = YES;
}
}
I have 2 view controllers, the first is a storyboard (this is root) and the second with is nibless. When I press a button in the root view controller it should call the second controller.
Here the code for my second view controller:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
UILabel *sampleLabel = [[UILabel alloc] initWithFrame: CGRectMake(0,0,100,100)];
UIImageView * basketItem = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"B.jpg"]];
[self.view addSubview:sampleLabel];
[self.view addSubview:basketItem];
NSLog(#"%#",self.view.subviews);
sampleLabel.text = #"Main Menu";
}
return self;
}
self.view.sebviews query shows that 2 objects label and imageView objects exists, but in fact I see black screen only.
Here is transition method
- (void)transitionToViewController:(UIViewController *)aViewController
withOptions:(UIViewAnimationOptions)options
{
aViewController.view.frame = self.containerView.bounds;
[UIView transitionWithView:self.containerView
duration:0.65f
options:options
animations:^{
[self.viewController.view removeFromSuperview];
[self.containerView addSubview:aViewController.view];
}
completion:^(BOOL finished){
self.viewController = aViewController;
}];
}
Move the code in viewDidLoad. Here you are sure the view has been loaded into memory and hence can be further customized.
- (void)viewDidLoad
{
[super viewDidLoad];
UILabel *sampleLabel = [[UILabel alloc] initWithFrame: CGRectMake(0,100,100,100)];
UIImageView * basketItem = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"B.jpg"]];
[self.view addSubview:sampleLabel];
[self.view addSubview:basketItem];
NSLog(#"%#",self.view.subviews);
sampleLabel.text = #"Main Menu";
}
If you are not using ARC, pay attention to memory leaks.
Note
I really suggest to read Apple doc for this. You should understand how things work. Hope that helps.
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html
Edit
I don't know what the problem could be. To make it work, try to override loadView (in MenuViewController) method like the following:
- (void)loadView
{
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
UIView *contentView = [[UIView alloc] initWithFrame:applicationFrame];
contentView.backgroundColor = [UIColor redColor]; // red color only for debug purposes
self.view = contentView;
}
Leave the viewDidLoad method as I wrote and see what happens.
When you create the view controller use only init method.
MenuViewController *vc = [[MenuViewController alloc] init];
Your UILabel's frame has size.width=0:
CGRectMake(0,100,0,100)
and if B.jpg is not added to the project you UIImageView will also be empty.
Also, if second UIViewController doesn't have a XIB, initialize it using the - (id)init method instead of - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil.