I am using the library AutoScrollLabel for autoScrollLabel like marquee and its working perfect when I need the label to scroll from left to right.
But when I have to use the direction from right to left I have facing this problem:
the label begin from the last word to the first?
Why?
You can find below my code:
self.autoScrollLabel.textColor = [UIColor whiteColor];
self.autoScrollLabel.labelSpacing = 1; // distance between start and end labels
self.autoScrollLabel.pauseInterval = 0;
self.autoScrollLabel.scrollSpeed = 70; // pixels per second
self.autoScrollLabel.textAlignment = NSTextAlignmentCenter;
self.autoScrollLabel.fadeLength = 0;
self.autoScrollLabel.scrollDirection = CBAutoScrollDirectionRight;
self.autoScrollLabel.text = [NSString stringWithFormat:#"%#%#",#"",#"hello hello1 hello1 heeloo3 hello3 hebe hehehe hgdghdhg he e e hehee hehee hehehehehehhe"];
I've never used AutoScrollLabel class, but I think in order to it worked properly you should change property
self.autoScrollLabel.scrollDirection = CBAutoScrollDirectionLeft
when you scroll to the left
for Swift you you can call this method :
func startMarqueeLabelAnimation() {
DispatchQueue.main.async(execute: {
UIView.animate(withDuration: 20.0, delay: 1, options: ([.curveLinear, .repeat]), animations: {() -> Void in
self.marqueeLabel.center = CGPoint(x: 0 - self.marqueeLabel.bounds.size.width / 2, y: self.marqueeLabel.center.y)
}, completion: nil)
})
}
Related
I investigated but I could not find anything like this for Swift. Can you please help me make this animation in Swift?
Val animador = ValueAnimator.ofFloat(0.0f ,1.0f)
animador.repeatCount = ValueAnimator.INFINITE
animador.interpolator= LinearInterpolator()
animador.duration = 10000L
animador.addUpdateListener { animation ->
val progreso = animador.animatedValue as Float
Val anchura = fondo!!.width
fondo!!.traslationx = transicionX
fondo2!!.traslationx = transicion X -anchura
}
animador.start()
This may not be exactly right, but try this:
let anchura = fondo.frame.width
UIView.animate(withDuration: 1, delay: 0, options: [.repeat, .autoreverse], animations: {
fondo.frame.origin.x = CGFloat(transicionX)
fondo2.frame.origin.x = CGFloat(transicionX) - anchura
})
Swift animations start automatically (no need to start() or anything).
Edit:
Inside the animations block, you just put the final value that you want. This means that you don't need to calculate the progress or anything, and you probably don't even need a transicionX variable. Instead, try this:
let anchura = fondo.frame.width /// let's say this is 50
UIView.animate(withDuration: 1, delay: 0, options: [.repeat, .autoreverse], animations: {
fondo.frame.origin.x += anchura /// move fondo to the right by 50
fondo2.frame.origin.x -= anchura /// move fondo2 to the left by 50
})
Another edit: made it += and -= to animate on top of existing values
I have to make a target appear and disappear randomly, e.g. in a space of 20 seconds but want to fix the flash first. The object is inserted programmatically and is just a png with collision. When the ball hits it, it disappears and the score is added. This part already works. Current code below
Spawn the enemy(is part of the function for the other 4 enemies)
let enemy1 = UIImageView(image: nil)
enemy1.image = UIImage(named: "enemy2.png")
enemy1.frame = CGRect(x: w*0.85, y: h*0.035, width: w*0.12, height: h*0.22)
self.view.addSubview(enemy1)
Add 1 to score when hit:
collisionBehaviour = UICollisionBehavior(items:[enemy1])
dynamicAnimator.addBehavior(collisionBehaviour)
collisionBehaviour.action = {
for boulderView in self.bouldersArray{
if boulderView.frame.intersects(enemy1.frame){
//enemy1.removeFromSuperview()
if enemy1.superview != nil{
self.scoreCount += 1
self.scoreCountLabel.text = "Score: \(self.scoreCount)"
enemy1.removeFromSuperview()
}
}
}
}
It's very hardcoded, please don't fix that. Tried an if statement to make it appear and disappear from subview, but it didn't work at all, just failed madly.
To make it disappear, set the alpha property to 0
enemy1.alpha = 0
To make it appear, set the alpha property to 1
enemy1.alpha = 1
if you wish to animate the disappearing use UIView Animate method
UIView.animate(withDuration: 0.3, delay: 0.5, options: .curveEaseOut, animations: {
self.enemy1.alpha = 0
}, completion: nil)
I try to close the menu animatedly using animation,
I decided to reduce the size of the UIScrollView on button press when size reduces up to my desired value, then I hide it.
to accomplish the task according to my desired user interface at some points, I had used the "time delay function" (300 milisec given)
everything goes well: if I don't press the button again and again until time limit reached
Error occurred: when i press button again and again before with in 300 milisec
func disAppearBlanceMenu(){
let x1 = btn_addBalance.clickableimg.frame.midX
let y1 = btn_addBalance.clickableimg.frame.maxY
UIView.animate(withDuration: 0.3) {
self.BalanceMenu.scrollview.frame = CGRect(x: x1 - 150, y: y1 + 20, width: 200, height: 20)
}
time.delay(milliSec: 300) {
self.BalanceMenu.triangle.isHidden = true
self.BalanceMenu.scrollview.isHidden = true
for i in 0...(self.BalanceMenuBtn.count - 1) {
self.BalanceMenuBtn[i].imag.removeFromSuperview()
self.BalanceMenuBtn[i].button.removeFromSuperview()
}
self.BalanceMenuBtn.removeAll()
}
displayBalanceMenu = true
}
Where
class time {
static func delay(milliSec:Int, code: #escaping () -> Void ) {
let deadline = DispatchTime.now() + .milliseconds(milliSec)
DispatchQueue.main.asyncAfter(deadline: deadline) {
code()
}
}
}
The error occurs here:
time.delay(milliSec: 300) {
It says
'Thread 1: Fatal error: Can't form Range with upperBound < lowerBound'
In your code, you should add a condition before executing the for loop like this :
time.delay(milliSec: 300) {
self.BalanceMenu.triangle.isHidden = true
self.BalanceMenu.scrollview.isHidden = true
if self.BalanceMenuBtn.count > 0 {
for i in 0...(self.BalanceMenuBtn.count - 1) {
self.BalanceMenuBtn[i].imag.removeFromSuperview()
self.BalanceMenuBtn[i].button.removeFromSuperview()
}
self.BalanceMenuBtn.removeAll()
}
}
You get this error when in for loop the lower bound is greater than the upper bound. In your code, when the first time the animation is completed then the count of the array will be 0 and for second time the condition would be like this
for I in 0...-1
That is why you are getting a crash and by checking the condition of the count as shown in my answer this would not crash.
Hope this helps.
It looks like you want to do something when the animation is done. If so, use its completion parameter:
UIView.animate(withDuration: 0.3, animations: {
self.BalanceMenu.scrollview.frame = CGRect(x: x1 - 150, y: y1 + 20, width: 200, height: 20)
}, completion: { _ in
self.BalanceMenu.triangle.isHidden = true
self.BalanceMenu.scrollview.isHidden = true
for button in self.BalanceMenuBtn {
button.imag.removeFromSuperview()
button.button.removeFromSuperview()
}
self.BalanceMenuBtn.removeAll()
})
It avoids timing problems introduced by that delay method. It also makes the intent more explicit.
Needless to say, once you get this immediate issue behind you, the properties BalanceMenu and BalanceMenuBtn should be renamed to start with lowercase letters, e.g., maybe balanceMenu and balanceMenuButtons, respectively. Also note the use of Buttons suffix rather than Btn, to make it clear it’s an array of buttons.
I wish I had more reputation so I could attach a screenshot of what I'm working on but you can see an example in the second link down below.
Basically there is a middle button in the tab bar which brings out option buttons (apple images in this case).
These apple icons are animated to their positions using UIDynamicAnimator and UIAttachmentBehavior.
Here is the code which adds the option buttons
func showOptions() {
var numberOfItems = self.delegate.brOptionsButtonNumberOfItems(self)
//NSAssert(numberOfItems > 0 , "number of items should be more than 0")
var angle = 0.0
var radius:Int = 20 * numberOfItems
angle = (180.0 / Double(numberOfItems))
// convert to radians
angle = angle/180.0 * M_PI
for(var i = 0; i<numberOfItems; i++) {
var csCalc = Float((angle * Double(i)) + (angle/2))
var buttonX = Float(radius) * cosf(csCalc)
var buttonY = Float(radius) * sinf(csCalc)
var wut = (angle * Double(i)) + (angle/2)
var brOptionItem = self.createButtonItemAtIndex(i)
var mypoint = self.tabBar.convertPoint(self.center, fromView:self.superview)
var x = mypoint.x + CGFloat(buttonX)
var y = self.frame.origin.y - CGFloat(buttonY)
var buttonPoint = CGPointMake(x, y)
//println("Button Point of Button Item x:\(x) y: \(y)")
brOptionItem.layer.anchorPoint = self.layer.anchorPoint
brOptionItem.center = mypoint
var attachment = UIAttachmentBehavior(item:brOptionItem, attachedToAnchor:buttonPoint)
attachment.damping = self.damping
attachment.frequency = self.frequency
attachment.length = 1
// set the attachment for dragging behavior
brOptionItem.attachment = attachment
self.dynamicItem!.addItem(brOptionItem)
//if(self.delegate.respondsToSelector("willDisplayButtonItem")) { //Fix me
//self.delegate.brOptionsButton(self, willDisplayButtonItem:brOptionItem)
//}
self.tabBar.insertSubview(brOptionItem, belowSubview: self.tabBar)
self.dynamicsAnimator!.addBehavior(attachment)
self.items.addObject(brOptionItem)
}
}
func createButtonItemAtIndex(indexz:NSInteger) -> BROptionsItem {
println("Create button item at index")
var brOptionItem = BROptionsItem(initWithIndex:indexz)
brOptionItem.addTarget(self, action:"buttonItemPressed:", forControlEvents:.TouchUpInside)
brOptionItem.autoresizingMask = UIViewAutoresizing.None
var image = self.delegate.brOptionsButton(self, imageForItemAtIndex:indexz)
//if((image) != nil) {
brOptionItem.setImage(image, forState: UIControlState.Normal)
//}
/*
var buttonTitle = self.delegate.brOptionsButton(self, titleForItemAtIndex:indexz)
if(buttonTitle.utf16Count > 0) {
brOptionItem.setTitle(buttonTitle, forState:UIControlState.Normal)
}
*/
return brOptionItem;
}
In showOptions the animator is assigned an attachment behavior for a brOptionItem that was just created when createButtomItemAtIndex was called.
In createButtonItemAtIndex, the brOptionItem is created and a target was added to execute a function when the button was tapped.
The option buttons work without the animation. I can click them and the target function is executed.
However, when the animation is added and the option buttons are placed where they are, nothing happens when the buttons are tapped.
I am extremely stuck on this. I have no idea why the animation stops the tapping actions. The buttons are supposed to be draggable as well.
Here is my source code. The code I reference can be see in the BROptiosnButton file.
https://github.com/WobbleDev/BROptionsSwift
Here is the reference code I used
https://github.com/BasheerSience/BROptionsButton
Thanks!
I am creating a PDFViewer application.
I have set the autoScale Property of the PDFViewer to true, so that it the view expands to the width of the screen.
Works fine with large PDF documents.
But when the document is a single page document, the page automatically scrolls down to the end of the page, instead of starting with the beginning.
I just cant understand the root cause of it.
What am I missing here?
This is what I did, it's a bit hacky
if let scrollView = pdfView.subviews.first as? UIScrollView {
scrollView.contentOffset.y = 0.0
}
I think this is a bug in PDFView.
As workaround I suggest to manually scroll top the top:
self.pdfView.document = pdfDocument;
NSPoint pt = NSMakePoint(0.0, [self.pdfView.documentView bounds].size.height);
[self.pdfView.documentView scrollPoint:pt];
Bug Reporter
rdar://37942090: PDFview scrolls to bottom of the page in single page document.
I propose this solution for scrolling to top of first page (it works on iOS 11.3):
if let document = pdfView.document,
let firstPage = document.page(at: 0)
{
let firstPageBounds = firstPage.bounds(for: pdfView.displayBox)
pdfView.go(to: CGRect(x: 0, y: firstPageBounds.height, width: 1.0, height: 1.0), on: firstPage)
}
Looks like the go command needs to be done on the next run through the run loop to work reliably:
DispatchQueue.main.async
{
guard let firstPage = pdfView.document?.page(at: 0) else { return }
pdfView.go(to: CGRect(x: 0, y: Int.max, width: 0, height: 0), on: firstPage)
}
Tested on iOS 12
Expanding on Petro's answer, I had some issues with rotated pages and cropped pages, but this seems to work universally. I actually tested it on rotated pages, along with an annotation in the corner to verify that I was selecting the right corner:
guard let firstPage = pdfView!.document?.page(at: 0) else {
return;
}
let firstPageBounds = firstPage.bounds(for: pdfView!.displayBox)
switch (firstPage.rotation % 360) {
case 0:
topLeftX = firstPageBounds.minX
topLeftY = firstPageBounds.maxY
case 90:
topLeftX = firstPageBounds.minX
topLeftY = firstPageBounds.minY
case 180:
topLeftX = firstPageBounds.maxX
topLeftY = firstPageBounds.minY
case 270:
topLeftX = firstPageBounds.maxX
topLeftY = firstPageBounds.maxY
default:
print ("Invalid rotation value, not divisible by 90")
}
pdfView!.go(to: CGRect(x: topLeftX, y: topLeftY, width: 1.0, height: 1.0), on: firstPage)
I was loading the document in viewDidLoad, then I moved it to viewDidAppear, and it worked for me.
The rotation of the PDFPage matters! This is the Objective-C version of Oded:
- (void)scrollToTopOfPage:(PDFPage *)page {
CGRect pageBounds = [page boundsForBox:self.displayBox];
CGFloat topLeftX = 0;
CGFloat topLeftY = 0;
switch (page.rotation % 360) {
case 0:
topLeftX = CGRectGetMinX(pageBounds);
topLeftY = CGRectGetMaxY(pageBounds);
break;
case 90:
topLeftX = CGRectGetMinX(pageBounds);
topLeftY = CGRectGetMinY(pageBounds);
break;
case 180:
topLeftX = CGRectGetMaxX(pageBounds);
topLeftY = CGRectGetMinY(pageBounds);
break;
case 270:
topLeftX = CGRectGetMaxX(pageBounds);
topLeftY = CGRectGetMaxY(pageBounds);
break;
default:
break;
}
[self goToRect:CGRectMake(topLeftX, topLeftY, 1, 1) onPage:page];
}
if let document = PDFDocument(url: viewModel.url) {
pdfView.document = document
// avoid iOS autoscale issue
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
self?.pdfView.autoScales = true
}
}
I used the work around to define the autoScales property a bit after the loading of the document. The first page is nicely fit on top then.
For Objective-C use:
PDFPage *firstPage = [pdfView.document pageAtIndex:0];
CGRect firstPageBounds = [firstPage boundsForBox:pdfView.displayBox];
[pdfView goToRect:CGRectMake(0, firstPageBounds.size.height, 1, 1) onPage:firstPage];