I receive a high resolution images from API, and I need to scale to fit them to my collection view cells. I'm using scaleToFit in UIImageView init but images are still in original ratio, moreover if I start to scroll in some moment they will get in full size
Cell:
final class SnapCarouselCellImpl: UICollectionViewCell, SnapCarouselCell{
var imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleToFill
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(imageView)
imageView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
imageView.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true
imageView.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true
}
VC:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SnapCarouselCell", for: indexPath) as! SnapCarouselCellImpl
let item = items[indexPath.row % items.count]
cell.imageView.image = UIImage(data: item.poster)
return cell
}
private func setUpCollectionView() -> UICollectionView{
let collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: flowLayout)
collectionView.showsHorizontalScrollIndicator = false
collectionView.frame = CGRect(x: 0, y: 100, width: view.frame.size.width, height: cellHeight * 1.2)
collectionView.decelerationRate = .init(rawValue: 20)
collectionView.register(SnapCarouselCellImpl.self, forCellWithReuseIdentifier: "SnapCarouselCell")
return collectionView
}
FlowLayout:
override func prepare() {
scrollDirection = .horizontal
minimumLineSpacing = 20
itemSize = CGSize(width: cellWidth, height: cellHeight)
let sideMargin = (collectionView!.bounds.width - cellWidth) / 2.0
sectionInset = UIEdgeInsets(top: 0.0, left: sideMargin, bottom: 0.0, right: sideMargin)
}
Result:
After scrolling:
You didn't provide enough code to confirm this, but...
You can probably correct the issue by changing this line in init in your SnapCarouselCellImpl class from:
addSubview(imageView)
to:
contentView.addSubview(imageView)
Related
I am trying to create a game that requires to create a textfield in SKScene. I have built the text field successfully, but bringing the keyboard down is the problem. This is my code so far.
import SpriteKit
import GameplayKit
import UIKit
class GameScene: SKScene {
var sceneFrame : CGRect = CGRect()
var textFieldFrame : CGRect = CGRect()
var textField : UITextField = UITextField()
var skView: SKView = SKView()
override func didMove(to view: SKView) {
sceneFrame = CGRect(origin: .zero, size: CGSize(width: 200, height: 200))
let scene = SKScene(size: sceneFrame.size)
scene.backgroundColor = UIColor.lightGray
textFieldFrame = CGRect(origin: .init(x: 100, y: 200), size: CGSize(width: 200, height: 30))
textField = UITextField(frame: textFieldFrame)
textField.backgroundColor = UIColor.white
textField.placeholder = "Phone Number"
textField.keyboardType = .numberPad
textField.resignFirstResponder()
self.view!.addSubview(textField)
self.view!.presentScene(scene)
// Where to put the textField.resignFirstResponder() ?
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
Any answers would be helpful.
The problem is you are not adding:
textfield.delegate = self
Then you could call the function:
func textFieldShouldReturn(textField: UITextField) -> Bool {
// Hides the keyboard
textField.resignFirstResponder()
return true
}
Declaring the delegate statement initiate the function textFieldShouldReturn.
Hope this helps :)
I am simply trying to display a CollectionView in playground to quickly try out ideas. Yet this has been a hour+ affair. I'm getting the error:
2017-03-17 17:28:37.862 uikitTest[88414:10270872] * Assertion failure in -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:viewCategory:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3600.6.21/UICollectionView.m:4971
2017-03-17 17:28:37.866 uikitTest[88414:10270872] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier test1 - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
*** First throw call stack:
I tried setting a view to the PlaygroundPage, and also creating a UIWindow. It isn't clear to me how to work with ViewControllers in Playground, and even whether this is the root problem and if its connected to the could not dequeue exception.
My Playground is as follows:
import UIKit
import XCPlayground
import PlaygroundSupport
class CVCCell: UICollectionViewCell {
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
label.frame = bounds
}
}
class CVC: UICollectionViewController {
var datasource = ["1","2","3"]
override func viewDidLoad() {
view.backgroundColor = .red
print(collectionView)
collectionView?.register(CVCCell.self, forCellWithReuseIdentifier: "test1")
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return datasource.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "test1", for: indexPath) as! CVCCell
cell.label.text = datasource[indexPath.row]
return cell
}
}
let containerView = UIView(frame: CGRect(x: 0.0,
y: 0.0,
width: 375.0,
height: 667.0))
containerView.backgroundColor = .green
let fl = UICollectionViewFlowLayout()
let cvc = CVC(collectionViewLayout: fl)
let w = UIWindow(frame: CGRect(x: 0, y: 0, width: 320, height: 480))
w.rootViewController = cvc
print(cvc.view)
containerView.addSubview(cvc.view)
//PlaygroundPage.current.liveView = containerView
I don't understand the problem here, my code has no bugs, but when I hit run nothing appears on the emulator. I need help, how can I see my images appear as a Scrollview on the emulator ?
import UIKit
class ViewController: UIViewController {
#IBOutlet var mainScrollView: UIScrollView!
var imageArray = [UIImage]()
override func viewDidLoad() {
mainScrollView.frame = view.frame
super.viewDidLoad()
imageArray = [#imageLiteral(resourceName: "IMG_1750"), #imageLiteral(resourceName: "IMG_1754")]
for i in 0..<imageArray.count{
let imageView = UIImageView()
imageView.image = imageArray[i]
imageView.contentMode = .scaleAspectFit
let xPosition = self.view.frame.width * CGFloat(i)
imageView.frame = CGRect(x: xPosition, y: 0, width: self.mainScrollView.frame.width, height: self.mainScrollView.frame.height)
mainScrollView.contentSize.width = mainScrollView.frame.width * CGFloat( i + 1)
mainScrollView.addSubview(imageView)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I am trying to use a GLIKit View in order to modify an Image. The class I have so far is working well all the CIFilters except for the CILineOverlay it renders a black view. If I use any other effect it works well.
Why is the CILineOverlay not showing?
class ImageView: GLKView {
let clampFilter = CIFilter(name: "CIAffineClamp")!
let blurFilter = CIFilter(name: "CILineOverlay")!
let ciContext:CIContext
override init(frame: CGRect) {
let glContext = EAGLContext(API: .OpenGLES2)
ciContext = CIContext(
EAGLContext: glContext,
options: [
kCIContextWorkingColorSpace: NSNull()
]
)
super.init(frame: frame, context: glContext)
enableSetNeedsDisplay = true
}
required init(coder aDecoder: NSCoder) {
let glContext = EAGLContext(API: .OpenGLES2)
ciContext = CIContext(
EAGLContext: glContext,
options: [
kCIContextWorkingColorSpace: NSNull()
]
)
super.init(coder: aDecoder)!
context = glContext
enableSetNeedsDisplay = true
}
#IBInspectable var inputImage: UIImage? {
didSet {
inputCIImage = inputImage.map { CIImage(image: $0)! }
}
}
#IBInspectable var blurRadius: Float = 0 {
didSet {
//blurFilter.setValue(blurRadius, forKey: "inputIntensity")
setNeedsDisplay()
}
}
var inputCIImage: CIImage? {
didSet { setNeedsDisplay() }
}
override func drawRect(rect: CGRect) {
if let inputCIImage = inputCIImage {
clampFilter.setValue(inputCIImage, forKey: kCIInputImageKey)
blurFilter.setValue(clampFilter.outputImage!, forKey: kCIInputImageKey)
let rect = CGRect(x: 0, y: 0, width: drawableWidth, height: drawableHeight)
ciContext.drawImage(blurFilter.outputImage!, inRect: rect, fromRect: inputCIImage.extent)
}
}
}
The Apple docs states "The portions of the image that are not outlined are transparent." - this means you are drawing black lines over a black background. You can simply composite the output from the filter over a white background to make the lines appear:
let background = CIImage(color: CIColor(color: UIColor.whiteColor()))
.imageByCroppingToRect(inputCIImage.extent)
let finalImage = filter.outputImage!
.imageByCompositingOverImage(background)
Question:
I've written a custom View Component in a playground but I can't figure out how to turn it into a custom class that I can use in the Interface Builder. Specifically, I'm confused as to how to make sure my custom view will resize correctly as the IB view is changed
Sub Question
I would also like to be able to use the #IBDesignable/#IBInspectable functionality as well if possible
Playground Code
import UIKit
let labelWidth : CGFloat = 200.0
var viewWidth : CGFloat = 200.0
let labelHeight: CGFloat = 60.0
var viewHeight : CGFloat = 60.0
let xOffset : CGFloat = 20
let yOffset : CGFloat = 20
let label = UILabel(frame: CGRectMake(0, 0 + 10, labelWidth, 50))
label.text = "Custom Text"
label.backgroundColor = UIColor.greenColor()
label.layer.masksToBounds = true
//label.layer.cornerRadius = 10.0
label.textAlignment = NSTextAlignment.Center
label
let titleLabel = UILabel(frame: CGRectMake(0,0,labelWidth,20))
titleLabel.font = UIFont(name: label.font.fontName, size: 10)
titleLabel.text = " TITLE"
titleLabel.layer.masksToBounds = true
titleLabel.backgroundColor = UIColor.whiteColor()
titleLabel
let v = UIView(frame: CGRectMake(0, 0, viewWidth, viewHeight))
v.backgroundColor = UIColor.grayColor()
v.addSubview(label)
v.addSubview(titleLabel)
v.layer.borderWidth = 1
v.layer.borderColor = UIColor.redColor().CGColor
v
Playground Visual Output
Note: Obviously these are not the final colors i want to use but they help differentiate the components
I just posted this answer for a similar question.
Here is a sample class to get you started.
import UIKit
#IBDesignable
class MyTabView: UIView {
#IBInspectable tabTitle: String = ""
#IBInspectable tabColor: UIColor = UIColor.clearColor()
override init(frame: CGRect) {
super.init(frame: frame)
// Initialization code
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func prepareForInterfaceBuilder() {
// stuff for interface builder only
}
override func drawRect(rect: CGRect)
{
// this is where your view gets drawed
self.layer.cornerRadius = 10
self.layer.masksToBounds = true
}
}
Note: you only need to override drawRect if you need custom drawing.