translationInView not working - xcode

I used this code many times but in my current project it isn't working. Here is the error (third line):
"No visible #interface for 'UIGestureRecognizer' declares the selector 'translationInView:'
and my simple code:
- (IBAction)panLayer:(UIGestureRecognizer *)pan{
if (pan.state == UIGestureRecognizerStateChanged) {
CGPoint point = [pan translationInView:self.view];
CGRect frame = self.settingsView.frame;
frame.origin.y = self.layerPosition + point.y;
if (frame.origin.y < 0) {
frame.origin.y = 0;
}
}

You are looking for the UIPanGestureRecognizer that has UIGestureRecognizer as the parent class.
- (IBAction)panLayer:(UIPanGestureRecognizer *)pan{
}

Related

NSCollectionViewAttributes not getting applied correctly with custom NSFlowLayout subclass

I'm currently working on an NSCollectionView with a custom layout. For that purpose, I subclassed NSCollectionViewFlowLayout to top-align my items (which all have a fixed width what made the algorithm pretty easy). The problem I have now is that only the first nine items in my collection view get displayed correctly, that is top-aligned.
These top nine items are at least partially visible when the collection view is initially displayed. The other items that appear when scrolling down the collection view will be drawn without any top-alignment, just vertically-centered-per-row as the default behaviour of NSCollectionViewFlowLayout. By extensive logging I could verify that my Layout only provides NSCollectionViewLayoutAttributes correctly modified for top-alignment.
When I resize the window containing the NSCollectionView, thus resizing the collection view itself, all items in the visible part of it will suddenly be displayed correctly.
What am I missing?
Here comes my custom subclass:
#import "MyCollectionViewLayout.h"
#interface MyCollectionViewLayout ()
#property (nonatomic, strong) NSMutableDictionary<NSIndexPath *, NSCollectionViewLayoutAttributes *> *attributesCache;
#property NSInteger numberOfItemsPerRow;
#property NSInteger numberOfItemsTotal;
#end
#implementation MyCollectionViewLayout
- (void)prepareLayout {
NSLog(#"Preparing layout");
[super prepareLayout];
self.itemSize = CGSizeMake(100, 138);
self.minimumInteritemSpacing = 5;
self.minimumLineSpacing = 5;
self.sectionInset = NSEdgeInsetsMake(10, 10, 10, 10);
self.attributesCache = #{}.mutableCopy;
self.numberOfItemsTotal = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:0];
NSInteger numberOfItemsPerRow = 1;
CGFloat computedSize = self.itemSize.width;
CGFloat usableWidth = self.collectionView.frame.size.width - (self.sectionInset.right + self.sectionInset.left);
repeat: {
computedSize += self.minimumInteritemSpacing + self.itemSize.width;
if (computedSize < usableWidth) {
numberOfItemsPerRow++;
goto repeat;
}
}
self.numberOfItemsPerRow = numberOfItemsPerRow;
}
#pragma mark NSCollectionViewFlowLayout override
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSLog(#"Getting layout attributes for rect: %f, %f, %f, %f", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
NSArray *attributesArray = [super layoutAttributesForElementsInRect:rect].mutableCopy;
for (int i = 0; i < attributesArray.count; i++) {
NSCollectionViewLayoutAttributes *attributes = attributesArray[i];
NSLog(#"Forwarding attribute request for %#", attributes.indexPath);
attributes = [self layoutAttributesForItemAtIndexPath:attributes.indexPath];
}
return attributesArray;
}
- (NSCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
if (!self.attributesCache[indexPath]) NSLog(#"");
NSLog(#"Getting layout attributes for %#", indexPath);
if (!self.attributesCache[indexPath]) {
NSLog(# "Not cached yet, caching full row");
[self computeAndCacheAttributesForRowContaining:indexPath];
}
return self.attributesCache[indexPath];
}
#pragma mark Private instance methods
- (void)computeAndCacheAttributesForRowContaining:(NSIndexPath *)indexPath {
NSDictionary<NSIndexPath *, NSCollectionViewLayoutAttributes *> *allAttributesInRowByPath = [self getAllAttributesInRowContaining:indexPath];
CGFloat minY = CGFLOAT_MAX;
for (NSIndexPath *path in allAttributesInRowByPath) {
if (allAttributesInRowByPath[path].frame.origin.y < minY) {
minY = allAttributesInRowByPath[path].frame.origin.y;
}
}
for (NSIndexPath *path in allAttributesInRowByPath) {
if (indexPath.item == 9) {
}
NSLog(#"Changing frame for indexPath %#", path);
NSRect frame = allAttributesInRowByPath[path].frame;
NSLog(#"Previous y Position: %f", frame.origin.y);
NSLog(#"New y Position: %f", minY);
frame.origin.y = minY;
allAttributesInRowByPath[path].frame = frame;
}
[self.attributesCache addEntriesFromDictionary:allAttributesInRowByPath];
}
- (NSDictionary<NSIndexPath *, NSCollectionViewLayoutAttributes *> *)getAllAttributesInRowContaining:(NSIndexPath *)indexPath {
NSMutableDictionary<NSIndexPath *, NSCollectionViewLayoutAttributes *> *attributesToReturn = #{}.mutableCopy;
NSInteger index = indexPath.item;
NSInteger firstIndex = index - (index % self.numberOfItemsPerRow);
NSIndexPath *path;
for (index = firstIndex; (index < firstIndex + self.numberOfItemsPerRow) && (index < self.numberOfItemsTotal); index++) {
path = [NSIndexPath indexPathForItem:index inSection:indexPath.section];
[attributesToReturn setObject:[super layoutAttributesForItemAtIndexPath:path].copy forKey:path];
}
return attributesToReturn.copy;
}
#end
You're missing attributesArray[i] = attributes; in layoutAttributesForElementsInRect : and are returning the unmodified attributes.
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSLog(#"Getting layout attributes for rect: %f, %f, %f, %f", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
NSMutableArray *attributesArray = [super layoutAttributesForElementsInRect:rect].mutableCopy;
for (int i = 0; i < attributesArray.count; i++) {
NSCollectionViewLayoutAttributes *attributes = attributesArray[i];
NSLog(#"Forwarding attribute request for %#", attributes.indexPath);
attributes = [self layoutAttributesForItemAtIndexPath:attributes.indexPath];
attributesArray[i] = attributes; // <---
}
return attributesArray;
}

Why layoutSubviews called twice?

I have subClass an UIView and override the layoutSubviews method.
When I called this subClass in my viewController,and add it to the controller's view,I found that "layoutSubviews" function have been called twice.
coverFlowView = CoverFlowView(frame: CGRectMake(0, 40, UIScreen.mainScreen().bounds.size.width, 480))
coverFlowView.delegate = self
coverFlowView.dataSource = self
self.view.addSubview(coverFlowView)
CoverFlowView is a view subclass UIView
I encountered the same problem.I tried different OS and got different result for same code flag:
one device only call layoutSubViews once, but another one called twice which caused one bug for my code...
My Code:
CGFloat step = 0.0;
if (self.array_rateOfEachColor) {
CGFloat sumRate = 0.0;
for (NSString *rate in self.array_rateOfEachColor) {
sumRate +=[rate floatValue];
}
NSAssert(sumRate != 1.0 , #" sum of all elemetns for array array_rateOfEachColor must be 1.0 ");
for (int i = 0 ; i < [self.mutableArray_layers count]; i ++) {
CGFloat step = [[_array_rateOfEachColor objectAtIndex:i] floatValue];
CAShapeLayer *tmp = [self.mutableArray_layers objectAtIndex:i];
[tmp setStrokeStart:self.strokeEndValue];
if (i == (self.mutableArray_layers.count -1)) { //the last layer
self.strokeEndValue = 1.0 - self.space ;
[tmp setStrokeEnd:self.strokeEndValue];
}else {
[tmp setStrokeEnd:self.strokeEndValue + step ];
}
self.strokeEndValue += (step + self.space); // record last strokeEndValue
}
}else{
step = 1.0 / self.mutableArray_layers.count; //average step
for (int i = 0 ; i < [self.mutableArray_layers count]; i ++) {
CAShapeLayer *tmp = [self.mutableArray_layers objectAtIndex:i];
[tmp setStrokeStart:self.strokeEndValue];
if (i == (self.mutableArray_layers.count -1)) { //the last layer
self.strokeEndValue = 1.0 - self.space ;
[tmp setStrokeEnd:self.strokeEndValue];
}else {
[tmp setStrokeEnd:self.strokeEndValue + step ];
}
self.strokeEndValue += (step + self.space); // record last strokeEndValue
}
}
self.strokeEndValue = 0.0; // different os , the layoutSubViews was called different times,so,this line is resolve this problem so that figure can be shown correctly
}

how to show UI objects code in xcode?

in one part of my project I need to create some UI objects programmatically, can I just customize my UI Objects like labels,... visually in storyboard then simply copy/paste generated code relevant to that object?
I searched in xcode menu but I couldn't find this but once I saw it in a tutorial in youtube.
Thanks in Advance
Yes you can customize the UI Classes or any other class, Like I have customize UILabel Class as UILabelExtended
UILabelExtended.h
#import <Foundation/Foundation.h>
/* **********************************************************************************************
This class inherit the class UILabel and extend the features of UILabel.
********************************************************************************************** */
#interface UILabelExtended : UILabel {
__unsafe_unretained id customDelegate;
id objectInfo;
SEL selector;
}
#property (nonatomic,assign) SEL selector;;
#property (nonatomic,assign) id customDelegate;
#property (nonatomic,retain) id objectInfo;
#end
#interface UILabel(UILabelCategory)
- (void)setHeightOfLabel;
- (void)setWidthOfLabel;
- (void)setHeightOfLabelWithMaxHeight:(float)maxHeight;
- (void)setWidthOfLabelWithMaxWidth:(float)maxWidth ;
#end
UILabelExtended.m
#import "UILabelExtended.h"
#implementation UILabelExtended
#synthesize selector,customDelegate, objectInfo;
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if(self.selector)
if([self.customDelegate respondsToSelector:self.selector]) {
[self.customDelegate performSelector:self.selector withObject:self];
return;
}
}
- (void)dealloc {
self.customDelegate = nil;
self.selector = NULL;
self.objectInfo = nil;
}
#end
#implementation UILabel(UILabelCategory)
- (void)setHeightOfLabel {
UILabel* label = self;
//get the height of label content
CGFloat height = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(label.bounds.size.width, 99999) lineBreakMode:NSLineBreakByWordWrapping].height;
//set the frame according to calculated height
CGRect frame = label.frame;
if([label.text length] > 0) {
frame.size.height = height;
}
else {
frame.size.height = 0;
}
label.frame = frame;
}
- (void)setWidthOfLabel {
UILabel* label = self;
//get the height of label content
CGFloat width = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(99999, label.bounds.size.height) lineBreakMode:NSLineBreakByWordWrapping].width;
//set the frame according to calculated height
CGRect frame = label.frame;
if([label.text length] > 0) {
frame.size.width = width+5;
}
else {
frame.size.width = 0;
}
label.frame = frame;
}
- (void)setHeightOfLabelWithMaxHeight:(float)maxHeight {
UILabel* label = self;
//get the height of label content
CGFloat height = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(label.bounds.size.width, maxHeight) lineBreakMode:NSLineBreakByWordWrapping].height;
//set the frame according to calculated height
CGRect frame = label.frame;
if([label.text length] > 0) {
if (height > maxHeight) {
frame.size.height = maxHeight;
}
else {
frame.size.height = height;
}
}
else {
frame.size.height = 0;
}
label.frame = frame;
}
- (void)setWidthOfLabelWithMaxWidth:(float)maxWidth {
UILabel* label = self;
//get the height of label content
CGFloat width = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(99999, label.bounds.size.height) lineBreakMode:NSLineBreakByWordWrapping].width;
//set the frame according to calculated height
CGRect frame = label.frame;
if([label.text length] > 0) {
if (width > maxWidth) {
frame.size.width = maxWidth;
}
else {
frame.size.width = width;
}
}
else {
frame.size.width = 0;
}
label.frame = frame;
}
#end

How do I implement scrollWheel elastic scrolling on OSX

I am trying to create a custom view, which is similar to NSScrollView, but is based on CoreAnimation CAScrollLayer/CATiledLayer. Basically, my app requires a lot of near realtime CGPath drawing, and animates these paths using shape layers (it's similar to the way GarageBand animates while recording). The first prototype I created used NSScrollView, but I could not get more than 20 frames per second with it (The reason was that NSRulerView updates by drawing every time the scrollEvent happens, and the entire call flow from -[NSClipView scrollToPoint] to -[NSScrollView reflectScrolledClipView:] is extremely expensive and inefficient).
I've created a custom view that uses CAScrollLayer as scrolling mechanism and CATiledLayer as the traditional documentView (for infinite scrolling option), and now I can get close to 60fps. However, I'm having hard time implementing scrollWheel elastic scrolling, and I'm not sure how to do it. Here's the code I have so far, and would really appreciate if someone can tell me how to implement elasticScrolling.
-(void) scrollWheel:(NSEvent *)theEvent{
NSCAssert(mDocumentScrollLayer, #"The Scroll Layer Cannot be nil");
NSCAssert(mDocumentLayer, #"The tiled layer cannot be nil");
NSCAssert(self.layer, #"The base layer of view cannot be nil");
NSCAssert(mRulerLayer, #"The ScrollLayer for ruler cannot be nil");
NSPoint locationInWindow = [theEvent locationInWindow];
NSPoint locationInBaseLayer = [self convertPoint:locationInWindow
fromView:nil];
NSPoint locationInRuler = [mRulerLayer convertPoint:locationInBaseLayer
fromLayer:self.layer];
if ([mRulerLayer containsPoint:locationInRuler]) {
return;
}
CGRect docRect = [mDocumentScrollLayer convertRect:[mDocumentLayer bounds]
fromLayer:mDocumentLayer];
CGRect scrollRect = [mDocumentScrollLayer visibleRect];
CGPoint newOrigin = scrollRect.origin;
CGFloat deltaX = [theEvent scrollingDeltaX];
CGFloat deltaY = [theEvent scrollingDeltaY];
if ([self isFlipped]) {
deltaY *= -1;
}
scrollRect.origin.x -= deltaX;
scrollRect.origin.y += deltaY;
if ((NSMinX(scrollRect) < NSMinX(docRect)) ||
(NSMaxX(scrollRect) > NSMaxX(docRect)) ||
(NSMinY(scrollRect) < NSMinY(docRect)) ||
(NSMaxY(scrollRect) > NSMaxX(docRect))) {
mIsScrollingPastEdge = YES;
CGFloat heightPhase = 0.0;
CGFloat widthPhase = 0.0;
CGSize size = [self frame].size;
if (NSMinX(scrollRect) < NSMinX(docRect)) {
widthPhase = ABS(NSMinX(scrollRect) - NSMinX(docRect));
}
if (NSMaxX(scrollRect) > NSMaxX(docRect)) {
widthPhase = ABS(NSMaxX(scrollRect) - NSMaxX(docRect));
}
if (NSMinY(scrollRect) < NSMinY(docRect)) {
heightPhase = ABS(NSMinY(scrollRect) - NSMinY(docRect));
}
if (NSMaxY(scrollRect) > NSMaxY(docRect)) {
heightPhase = ABS(NSMaxY(scrollRect) - NSMaxY(docRect));
}
if (widthPhase > size.width/2.0) {
widthPhase = size.width/2.0;
}
if (heightPhase > size.width/2.0) {
heightPhase = size.width/2.0;
}
deltaX = deltaX*(1-(2*widthPhase/size.width));
deltaY = deltaY*(1-(2*heightPhase/size.height));
}
newOrigin.x -= deltaX;
newOrigin.y += deltaY;
if ( mIsScrollingPastEdge &&
(([theEvent phase] == NSEventPhaseEnded) ||
([theEvent momentumPhase] == NSEventPhaseEnded)
)
){
CGPoint confinedScrollPoint = [mDocumentScrollLayer bounds].origin;
mIsScrollingPastEdge = NO;
CGRect visibleRect = [mDocumentScrollLayer visibleRect];
if (NSMinX(scrollRect) < NSMinX(docRect)){
confinedScrollPoint.x = docRect.origin.x;
}
if(NSMinY(scrollRect) < NSMinY(docRect)) {
confinedScrollPoint.y = docRect.origin.y;
}
if (NSMaxX(scrollRect) > NSMaxX(docRect)) {
confinedScrollPoint.x = NSMaxX(docRect) - visibleRect.size.width;
}
if (NSMaxY(scrollRect) > NSMaxY(docRect)){
confinedScrollPoint.y = NSMaxY(docRect) - visibleRect.size.height;
}
[mDocumentScrollLayer scrollToPoint:confinedScrollPoint];
CGPoint rulerPoint = [mRulerLayer bounds].origin;
rulerPoint.x = [mDocumentLayer bounds].origin.x;
[mRulerLayer scrollToPoint:rulerPoint];
return;
}
CGPoint rulerPoint = [mDocumentScrollLayer convertPoint:newOrigin
toLayer:mRulerLayer];
rulerPoint.y = [mRulerLayer bounds].origin.y;
if (!mIsScrollingPastEdge) {
[CATransaction setDisableActions:YES];
[mDocumentScrollLayer scrollToPoint:newOrigin];
[CATransaction commit];
}else{
[mDocumentScrollLayer scrollToPoint:newOrigin];
[mRulerLayer scrollToPoint:rulerPoint];
}
}
Take a look at TUIScrollView at https://github.com/twitter/twui.
The Core concept of adding ElasticScrolling is to use a SpringSolver.
This has a ElasticScrollView that you can reuse:
https://github.com/eonist/Element

Cocos2d: Animation based on accelerometer

Anyone know of any good up to date tutorials out there that show how can one animate a sprite based on accelerometer movement. I want to animate a bird to sway to the position the device was pointed to. For example if the player decides to move the bird to the left via the accelerometer I would like for my bird to play an animation that is swaying to the left.
// Accelerometer
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
birdSpeedY = 9.0 + acceleration.x*15;
birdSpeedX = -acceleration.y*20;
}
// Updating bird based on accelerometer
-(void)updateBird {
float maxY = winSize.height - bird.contentSize.height/2;
float minY = bird.contentSize.height/2;
float newY = bird.position.y + birdSpeedY;
newY = MIN(MAX(newY, minY), maxY);
float maxX = winSize.width - bird.contentSize.width/2;
float minX = bird.contentSize.width/2;
float newX = bird.position.x + birdSpeedX;
newX = MIN(MAX(newX, minX), maxX);
bird.position = ccp(newX, newY);
}
// Making background scroll automatically
-(void)update:(ccTime)dt {
[self updateBird];
CGPoint backgroundScrollVel = ccp(-100, 0);
parallaxNode.position = ccpAdd(parallaxNode.position, ccpMult(backgroundScrollVel, dt));
}
-(id)init {
self = [super init];
if (self != nil) {
winSize = [CCDirector sharedDirector].winSize;
CCSpriteFrameCache *cache=[CCSpriteFrameCache sharedSpriteFrameCache];
[cache addSpriteFramesWithFile:#"birdAtlas.plist"];
NSMutableArray *framesArray=[NSMutableArray array];
for (int i=1; i<10; i++) {
NSString *frameName=[NSString stringWithFormat:#"bird%d.png", i];
id frameObject=[cache spriteFrameByName:frameName];
[framesArray addObject:frameObject];
}
// animation object
id animObject=[CCAnimation animationWithFrames:framesArray delay:0.1];
// animation action
id animAction=[CCAnimate actionWithAnimation:animObject restoreOriginalFrame:NO];
animAction=[CCRepeatForever actionWithAction:animAction];
bird=[CCSprite spriteWithSpriteFrameName:#"bird1.png"];
bird.position=ccp(60,160);
CCSpriteBatchNode *batchNode=[CCSpriteBatchNode batchNodeWithFile:#"birdAtlas.png"];
[self addChild:batchNode z:100];
[batchNode addChild:bird];
[bird runAction:animAction];
self.isAccelerometerEnabled = YES;
[self scheduleUpdate];
[self addScrollingBackgroundWithTileMapInsideParallax];
}
return self;
}
- (void) dealloc
{
[super dealloc];
}
#end
You can try the Accelerometer methods with it and change the position of the Sprite using ccp(). You also need to know is that project for the Landscape or Portrait in the Mode.
You Can Try the Stuff below
- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
{
[lbl setString:[NSString stringWithFormat:#"X=>%.2lf Y=>%.2lf",(double)acceleration.x,(double)acceleration.y]];
double x1= -acceleration.y *10;
double y1= acceleration.x *15;
if(acceleration.x >0.05)
{
y1*=spped_incr; // Make Movement Here
}
[Sprite_Name runAction:[CCMoveTo actionWithDuration:0.1f position:ccpAdd(ccp(x1,y1), Sprite_Name.position)]];
}
The Above Stuff is for the Landscape Mode.... if You need in Portrait Mode you need to change the Axis and use the TRY & Error Method.

Resources