I am attempting to create an iOS LineNumberLayoutManger in Swift to be used in a TextKit 2 UITextView. My problem is the line number variable is being overwritten when I enter a new line with the return key. The revised code sample below can be copied and pasted into an Xcode project in a ViewController to run. Any suggestions very much appreciated.
// ViewController.swift
// tester11
//
// Created by ianshortreed on 2022/07/15.
//
import UIKit
var currentRect:CGRect!
var cgPoint:CGPoint!
extension String {
func substring(with range: NSRange) -> String {
let startIndex = index(self.startIndex, offsetBy: range.location)
let endIndex = index(startIndex, offsetBy: range.length)
//return substring(with: startIndex ..< endIndex)
return String(self[startIndex..<endIndex])
}
}
extension Collection {
var enumerated: Zip2Sequence<PartialRangeFrom<Int32>, Self> { zip(1..., self) }
}
class ViewController: UIViewController, UITextViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
createTextView()
}
func createTextView() {
var textView: UITextView!
var textStorage: NSTextStorage!
// 1
let attrs = [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .body), .foregroundColor: UIColor.label]
let attrString = NSAttributedString(string: "Press the return key to add a new line.", attributes: attrs)
textStorage = NSTextStorage()
textStorage.append(attrString)
let newTextViewRect = view.bounds
// 2
//let layoutManager = LineNumberLayoutManager()
let layoutManager = LineNumberLayoutManager()
// 3
let containerSize = CGSize(width: newTextViewRect.width, height: .greatestFiniteMagnitude)
let container = NSTextContainer(size: containerSize)
container.widthTracksTextView = true
layoutManager.addTextContainer(container)
textStorage.addLayoutManager(layoutManager)
// 4
textView = UITextView(frame: newTextViewRect, textContainer: container)
textView.delegate = self
textView.isScrollEnabled = true
textView.textContainerInset = .zero
textView.textContainer.lineFragmentPadding = 9.5
//textView.layoutManager.usesFontLeading = false
textView.keyboardDismissMode = .interactive
textView.textContainerInset = UIEdgeInsets(top: 50, left: 10, bottom: 0, right: 10)
textView.typingAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17)]
textView.textAlignment = NSTextAlignment.justified
textView.allowsEditingTextAttributes = true
textView.isSelectable = true
textView.isUserInteractionEnabled = true
textView.dataDetectorTypes = .all
view.addSubview(textView)
// 5
textView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
textView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
textView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
textView.topAnchor.constraint(equalTo: view.topAnchor),
textView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
class LineNumberLayoutManager: NSLayoutManager {
let lineSize = CGSize(width: 8, height: 8)
var lineColor = UIColor(red:1.00, green:1.00, blue:1.00, alpha:1.0)
override func drawGlyphs(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint) {
var linenumber = 0
super.drawGlyphs(forGlyphRange: glyphsToShow, at: origin)
guard let textStorage = self.textStorage else { return }
enumerateLineFragments(forGlyphRange: glyphsToShow) { [self] (rect, usedRect, textContainer, glyphRange, _) in
linenumber += 1
let origin = CGPoint(x: 10, y: usedRect.origin.y + 48 + (usedRect.size.height - self.lineSize.height) / 2)
var newLineRange = NSRange(location: 0, length: 0)
if glyphRange.location > 0 {
newLineRange.location = glyphRange.location - 1
newLineRange.length = 1
}
var isNewLine = true
if newLineRange.length > 0 {
isNewLine = textStorage.string.substring(with: newLineRange) == "\n"
}
if isNewLine {
let str = textStorage.string.components(separatedBy: .newlines)
"\(linenumber)\(str)".draw(in:CGRect(origin: origin, size: lineSize))
}
}
}
}
}
I need to download images I created a alamofire post request with parameter i dont have any problem in that . After that i need to download the image url from the Json response generated, I dont know how to download the image url from json and keep that in a array , after that have to download the inage from the url need to bind it in a image view of collectionView . I dont have any idea about how to take the image url from the json response then keep that in a array , then have to download the image bind it in a collectionView. Please help me
I have updated the json response for my post request. please give me a solution. I can get the below response in console.
( {
ActualPrice = 0;
AssuredTitle = "<null>";
CashBackAmount = 0;
CashBackDiscountPercentage = 0;
Code = "";
Cost = "<null>";
CreateDate = "<null>";
CustomSize = 0;
Delivery = "<null>";
DeliveryDate = "<null>";
DeliveryDays = "<null>";
Designer = "<null>";
Discount = "<null>";
DiscountCost = "<null>";
DispatchDateDisplay = "<null>";
Exclusive = "<null>";
Gender = "<null>";
HasReadyMadeColor = 0;
HasReadyMadeSizes = 0;
ID = 41;
ImageUrl = "https://images.cbazaar.com/images/aqua-blue-georgette-abaya-isbs1805991-u.jpg";
Is7DD = "<null>";
IsCustomizable = 0;
IsExclusive = 0;
IsFree = "<null>";
IsFreeShipping = 0;
IsInWishlist = 0;
IsLookUp = 0;
IsNew = 0;
IsProductAnimation = 0;
IsReadyToShip = 0;
LargeImageUrl = "<null>";
ListingImage = "<null>";
LowerLargeImage = "<null>";
LowerThumbImage = "<null>";
MoneyFactor = "<null>";
MoneyOffFactor = "<null>";
Name = "Islamic wear";
OfferImageUrl = "<null>";
OldPrice = 0;
OutOfStock = 0;
PDUrl = "<null>";
ProductBigLink = "<null>";
ProductCollectionReference = "<null>";
ProductHisImage = "<null>";
ProductSaleCycle = 0;
ProductType = 168;
ProductV2VRatio = 0;
PromotionTypeID = "<null>";
Promotions = "<null>";
PromotionsIcon = "<null>";
Rating = "<null>";
SalePrice = "<null>";
ShowOldPrice = 0;
SizeChart = "<null>";
SuperClassification = "<null>";
TypeGroup = "<null>";
TypeShortCode = "<null>";
UpperLargeImage = "<null>";
UpperThumbImage = "<null>";
VendorType = "<null>";
VisitCount = 0;
})
Complete ViewController File
import UIKit
import Alamofire
import AlamofireImage
class EthnoVogueDesignConsultationViewController: UIViewController, UIScrollViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var header_scrollView: UIScrollView!
#IBOutlet weak var pagecontroller: UIPageControl!
#IBOutlet weak var step_label: UILabel!
#IBOutlet weak var segmented_View: UIView!
#IBOutlet weak var segmented_Control: UISegmentedControl!
#IBOutlet weak var stylistView: UIView!
#IBOutlet weak var categorycollectionview: UICollectionView!
#IBOutlet weak var pagecontrollerview: UIView!
let image_array = ["slider1","slider2","slider1","slider2"]
let name_label = ["Salwar kameez","saree", "Anarkali", "Leghenga"]
static var deepLinkingFlag:Int = 0
static var deepLinkingFlagAfterKilling:Int = 0
var httpObj = HTTPHelper()
var apiRequestParameters:NSMutableDictionary = NSMutableDictionary()
var dictResult: NSDictionary = NSDictionary()
// var imageCache = [String:UIImage]()
//Array of images from the URL
var imageArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
globalConstants.deepLinkingFlagAfterKilling = 0
globalConstants.deepLinkingFlag = 0
apiclass()
// imagedownload()
//View which holds the stylist Name
stylistView.backgroundColor = UIColor(red: 235/255, green: 232/255, blue: 232/255, alpha: 1)
pagecontrollerview.backgroundColor = UIColor(red: 235/255, green: 232/255, blue: 232/255, alpha: 1)
//Label with holds the step 1
step_label.layer.borderWidth = 2
step_label.layer.borderColor = UIColor(red: 249/255, green: 8/255, blue: 129/255, alpha: 1).cgColor
stylistView.layer.shadowOffset = CGSize(width: 1, height: 1)
step_label.layer.shadowOpacity = 4
step_label.layer.shadowColor = UIColor(red: 249/255, green: 8/255, blue: 129/255, alpha: 1).cgColor
//Customising the segmented control with background color and tint color, font size
segmented_Control.tintColor = UIColor(red: 249/255, green: 8/255, blue: 129/255, alpha: 1)
segmented_Control.backgroundColor = UIColor.white
segmented_Control.layer.cornerRadius = 20
// let font = UIFont.systemFont(ofSize: 20)
let font = UIFont.boldSystemFont(ofSize: 20)
segmented_Control.setTitleTextAttributes([NSAttributedStringKey.font: font],
for: .normal)
let cellSize = CGSize(width:250 , height:400)
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = cellSize
layout.sectionInset = UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
layout.minimumLineSpacing = 10.0
layout.minimumInteritemSpacing = 10.0
categorycollectionview.setCollectionViewLayout(layout, animated: true)
categorycollectionview.setCollectionViewLayout(layout, animated: false)
categorycollectionview.delegate = self
categorycollectionview.dataSource = self
// Do any additional setup after loading the view, typically from a nib.
self.header_scrollView.frame = CGRect(x:0, y:0, width:self.view.frame.width, height:225)
let scrollViewWidth:CGFloat = self.header_scrollView.frame.width
let scrollViewHeight:CGFloat = self.header_scrollView.frame.height
header_scrollView.backgroundColor = UIColor.black
//set image to the particular image in uiscrollview
let imgOne = UIImageView(frame: CGRect(x:0, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgOne.image = UIImage(named: "slider2")
let imgTwo = UIImageView(frame: CGRect(x:scrollViewWidth, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgTwo.image = UIImage(named: "slider1")
//Adding subview for the scrollview
self.header_scrollView.addSubview(imgOne)
self.header_scrollView.addSubview(imgTwo)
//setting size of the content view
self.header_scrollView.contentSize = CGSize(width:self.header_scrollView.frame.width * 4, height:self.header_scrollView.frame.height)
//header scroll view delegate selection
self.header_scrollView.delegate = self
self.pagecontroller.currentPage = 0
// time interval to move the slide show
Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(moveToNextPage), userInfo: nil, repeats: true)
//step label for rounded corners
step_label.layer.masksToBounds = true
step_label.layer.cornerRadius = 15.0
NotificationCenter.default.addObserver(self, selector: #selector(EthnoVogueDesignConsultationViewController.deepLinking(_:)), name:NSNotification.Name(rawValue: "deepLinking"), object: nil)
}
#objc func deepLinking(_ notification:Notification){
print("its here")
// globalConstants.isSortCleared = 0
if(globalConstants.deepLinkingFlag == 1){
self.tabBarController?.selectedIndex = 0
// let viewController = self.storyboard?.instantiateViewController(withIdentifier:"catalog") as? CatalogController
// self.navigationController?.pushViewController(viewController!, animated: false)
}
else if(globalConstants.deepLinkingFlag == 2){
self.tabBarController?.selectedIndex = 0
// let viewController = self.storyboard?.instantiateViewController(withIdentifier:"productDetails") as? ProductDetailViewController
// self.navigationController?.pushViewController(viewController!, animated: false)
}
else if(globalConstants.deepLinkingFlag == 3){
self.tabBarController?.selectedIndex = 0
// let viewController = self.storyboard?.instantiateViewController(withIdentifier:"ols") as? OLSViewController
// self.navigationController?.pushViewController(viewController!, animated: false)
}
else if(globalConstants.deepLinkingFlag == 4){
self.tabBarController?.selectedIndex = 0
// let viewController = self.storyboard?.instantiateViewController(withIdentifier:"home") as? HomeController
// self.navigationController?.pushViewController(viewController!, animated: false)
}
else if(globalConstants.deepLinkingFlag == 5){
//self.navigationController?.popToRootViewControllerAnimated(false)
self.tabBarController?.selectedIndex = 1
}
else if(globalConstants.deepLinkingFlag == 6){
//self.navigationController?.popToRootViewControllerAnimated(false)
self.tabBarController?.selectedIndex = 2
}
else if(globalConstants.deepLinkingFlag == 7){
//self.navigationController?.popToRootViewControllerAnimated(false)
self.tabBarController?.selectedIndex = 0
}
}
// move to next image image view in file
#objc func moveToNextPage (){
let pageWidth:CGFloat = self.header_scrollView.frame.width
let maxWidth:CGFloat = pageWidth * 2
let contentOffset:CGFloat = self.header_scrollView.contentOffset.x
var slideToX = contentOffset + pageWidth
if contentOffset + pageWidth == maxWidth
{
slideToX = 0
}
self.header_scrollView.scrollRectToVisible(CGRect(x:slideToX, y:0, width:pageWidth, height:self.header_scrollView.frame.height), animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//scrollView Method for chaning the page control while swiping the image
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pagenumber = scrollView.contentOffset.x / scrollView.frame.size.width
pagecontroller.currentPage = Int(pagenumber)
}
//CollectionView for Categories image
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch segmented_Control.selectedSegmentIndex {
case 0:
return imageArray.count
case 1:
return 10
default:
break
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imagecell", for: indexPath) as! CategorySegmentCollectionViewCell
let url = NSURL(string: self.imageArray[indexPath.item])!
Cell.category_image.af_setImage(withURL: url as URL, placeholderImage: UIImage(named: "noimage.png"), filter: nil, imageTransition: .noTransition, runImageTransitionIfCached: true, completion: nil)
switch segmented_Control.selectedSegmentIndex{
case 0:
// let img : UIImage = UIImage(named:"pink")!
//
// Cell.category_image.image = img
// Cell.category_name_label.text = name_label[indexPath.item]
break
case 1:
// let img : UIImage = UIImage(named:"dark")!
// Cell.category_image.image = img
// Cell.category_name_label.text = "condition"
break
default:
break
}
//let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "brandCell", for: indexPath) as! BrandCollectionViewCell
// use this to download images
return Cell
}
func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? CategorySegmentCollectionViewCell {
cell.category_image.transform = .init(scaleX: 0.95, y: 0.95)
cell.contentView.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.95, alpha: 1)
}
}
}
func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? CategorySegmentCollectionViewCell {
cell.category_image.transform = .identity
cell.contentView.backgroundColor = .clear
}
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
switch segmented_Control.selectedSegmentIndex{
case 0:
if (collectionView.cellForItem(at: indexPath) as? CategorySegmentCollectionViewCell) != nil {
self.segmented_Control.setEnabled(true, forSegmentAt: 1)
segmented_Control.selectedSegmentIndex = 1
collectionView.reloadData()
//print(cell)
}
break
case 1:
if (collectionView.cellForItem(at: indexPath) as? CategorySegmentCollectionViewCell) != nil {
self.segmented_Control.setEnabled(true, forSegmentAt: 2)
let categoryTaskVC = storyboard?.instantiateViewController(withIdentifier: "fabrics") as! FabricsViewController
self.navigationController?.pushViewController(categoryTaskVC, animated: true)
}
break
default:
break
}
}
override func viewWillAppear(_ animated: Bool) {
if(segmented_Control.selectedSegmentIndex == 0){
self.segmented_Control.setEnabled(false, forSegmentAt: 1)
self.segmented_Control.setEnabled(false, forSegmentAt: 2)
}
}
#IBAction func segmented_tapped_action(_ sender: Any) {
categorycollectionview.reloadData()
}
func apiclass(){
if(globalConstants.prefs.value(forKey: "authToken") == nil){
self.httpObj.getAuthToken()
}
else if(globalConstants.prefs.value(forKey: "authExpireDate") != nil && Date().compare((globalConstants.prefs.value(forKey: "authExpireDate") as? Date)!) == ComparisonResult.orderedDescending){
globalConstants.prefs.setValue(nil, forKey: "authToken")
self.httpObj.getAuthToken()
}
DispatchQueue.main.async(execute: {
if(globalConstants.prefs.value(forKey: "authToken") != nil){
var request:NSMutableURLRequest = NSMutableURLRequest(url: globalConstants.tokenUrl as URL)
let authToken:String = (globalConstants.prefs.value(forKey: "authToken") as? String)!
request = NSMutableURLRequest(url: globalConstants.tokenUrl as URL)
request.addValue("Bearer \(authToken)", forHTTPHeaderField: "Authorization")
request.addValue(UIDevice.current.identifierForVendor!.uuidString, forHTTPHeaderField: "X-Device-ID")
request.addValue((globalConstants.prefs.value(forKey: "UUID") as? String)!, forHTTPHeaderField: "X-Unique-ID")
request.addValue((globalConstants.prefs.value(forKey: "countryCode") as? String)!, forHTTPHeaderField: "X-Country-Code")
request.addValue((globalConstants.prefs.value(forKey: "currencyCode") as? String)!, forHTTPHeaderField: "X-Currency-Code")
request.addValue((globalConstants.prefs.value(forKey: "currencySymbol") as? String)!, forHTTPHeaderField: "X-Currency-Symbol")
request.addValue(String(stringInterpolationSegment: (globalConstants.prefs.value(forKey: "currencyFactor"))!), forHTTPHeaderField: "X-Currency-Factor")
request.addValue((globalConstants.prefs.value(forKey: "appSource") as? String)!, forHTTPHeaderField: "X-App-Source")
request.addValue(globalConstants.appVersion, forHTTPHeaderField: "X-App-Version")
request.addValue(String(stringInterpolationSegment: (globalConstants.prefs.value(forKey: "estoreId") as? Int)!), forHTTPHeaderField: "X-EStore-ID")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
if(globalConstants.prefs.value(forKey: "userEmail") != nil){
request.addValue((globalConstants.prefs.value(forKey: "userEmail") as? String)!, forHTTPHeaderField: "X-Email")
}
if(globalConstants.prefs.value(forKey: "userId") != nil){
request.addValue(String(stringInterpolationSegment: (globalConstants.prefs.value(forKey: "userId"))!), forHTTPHeaderField: "X-User-ID")
}
print(self.apiRequestParameters)
var requestParameters:NSMutableDictionary = NSMutableDictionary()
requestParameters = [
"mode" : "design",
"productGroup" : 0
]
print(requestParameters)
request.url = globalConstants.ESDCUrl as URL
self.httpObj.sendRequest("POST", requestDict: requestParameters, request: request as URLRequest, completion: { (result, error) in
print(result!)
if(error == nil){
guard let json = result as! [[String:Any]]? else{
return
}
print("Response \(json)")
for images in json
{
if let ImageUrl = images["ImageUrl"] as? String
{
self.imageArray.append(ImageUrl)
}
DispatchQueue.main.async {
self.categorycollectionview.reloadData()
}
}
// self.dictResult = result as! NSDictionary
// self.categorycollectionview.reloadData()
//self.collectionView.reloadData()
// let requestDataDict:NSDictionary = incomingRequetArray[0] as! NSDictionary
// let newDict: NSURL = requestDataDict.object(forKey: "ImageUrl") as? NSDictionary
//
}
else{
let alert = UIAlertView()
alert.isHidden = true
alert.addButton(withTitle: "OK")
alert.message = globalConstants.apiErrorMessage
alert.show()
}
})
}
})
}
//typealaising the headerscrollview to the view controller
private typealias Header_scrollView = EthnoVogueDesignConsultationViewController
// extending the header_scrollview
extension Header_scrollView
{
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView){
// Test the offset and calculate the current page after scrolling ends
let pageWidth:CGFloat = scrollView.frame.width
let currentPage:CGFloat = floor((scrollView.contentOffset.x-pageWidth/2)/pageWidth)+1
// Change the indicator
self.pagecontroller.currentPage = Int(currentPage);
UIView.animate(withDuration: 1.0, animations: { () -> Void in
// self.startButton.alpha = 1.0
})
}
}
My application supports multiple languages. I have a Translation object which sets string on NSButton Title. How can I use multiline to set text inside my Button?
I used self.lineBreakMode = .ByWordWrapping but it does not work.
class CustomNSButton: NSButton {
override func viewWillDraw() {
let currentText = Translations.shared.current?[self.identifier ?? ""]?.string ?? self.stringValue
self.lineBreakMode = .byWordWrapping
let size = calculateIdealFontSize(min: 5, max: 16)
let translatedString = CustomFormatter.string(for: currentText)
let pstyle = NSMutableParagraphStyle()
pstyle.alignment = .center
let translatedAttributedString = CustomFormatter.attributedString(for: translatedString ?? "", withDefaultAttributes:[NSFontAttributeName : NSFont(name: (self.font?.fontName)!, size: CGFloat(size))!, NSParagraphStyleAttributeName : pstyle])!
attributedTitle = translatedAttributedString
}
}
I created a multiline text by using let textLabel = NSTextField() and a let textFieldCell = CustomNSTextFieldCell() subclass. Add subview in CustomNSButton class addSubview(textLabel)
class CustomNSButton: NSButton {
let textLabel = NSTextField()
let textFieldCell = CustomNSTextFieldCell()
override func viewWillDraw() {
textLabel.frame = CGRect(x:0,y:0, width: frame.width - 2, height: frame.height - 2)
let pstyle = NSMutableParagraphStyle()
pstyle.alignment = .center
textLabel.attributedStringValue = CustomFormatter.attributedString(for: translatedString ?? "", withDefaultAttributes:[NSFontAttributeName : NSFont(name: (self.font?.fontName)!, size: CGFloat(size))!, NSParagraphStyleAttributeName : pstyle, NSForegroundColorAttributeName : NSColor.white])!
textLabel.isEditable = false
textLabel.isBezeled = false
textLabel.backgroundColor = NSColor.clear
textLabel.cell = textFieldCell
addSubview(textLabel)
}
}
class CustomNSTextFieldCell: NSTextFieldCell {
override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
let attrString: NSAttributedString? = attributedStringValue
attrString?.draw(with: titleRect(forBounds: cellFrame), options: [.truncatesLastVisibleLine, .usesLineFragmentOrigin])
}
override func titleRect(forBounds theRect: NSRect) -> NSRect {
var tFrame: NSRect = super.titleRect(forBounds: theRect)
let attrString: NSAttributedString? = attributedStringValue
let tRect: NSRect? = attrString?.boundingRect(with: tFrame.size, options: [.truncatesLastVisibleLine, .usesLineFragmentOrigin])
if (textRect?.size.height)! < tFrame.size.height {
tFrame.origin.y = theRect.origin.y + (theRect.size.height - (textRect?.size.height)!) / 2.0
tFrame.size.height = (textRect?.size.height)!
}
return tFrame
}
}
I'm trying to print entire NSCollectionView. It prints only displayed items, moreover it doesn't render NSCollectionViewItem properly
Print is populated by bindings using first responder. Method:
#IBAction func printEquations(_ sender: Any) {
let op = NSPrintOperation(view: collectionView)
op.canSpawnSeparateThread = true
let pi = op.printInfo
pi.horizontalPagination = NSPrintingPaginationMode.fitPagination
pi.verticalPagination = NSPrintingPaginationMode.fitPagination
pi.isHorizontallyCentered = true
pi.isVerticallyCentered = true
pi.isSelectionOnly = false
pi.orientation = NSPaperOrientation.portrait
pi.leftMargin = 10
pi.rightMargin = 10
op.run()
}
NSCollectionView subclass:
class EQCollectionView: NSCollectionView {
var printRect: NSRect?
override func draw(_ dirtyRect: NSRect) {
if (NSGraphicsContext.currentContextDrawingToScreen()) {
self.layer!.borderWidth = 0
self.layer!.borderColor = nil
self.backgroundColors = []
super.draw(dirtyRect)
} else {
self.wantsLayer = true
let printWidth = Double(calculatePrintWidth())
let printHeight = Double(calculatePrintHeight())
printRect = NSRect(x: 0, y: 0, width: printWidth, height: printHeight)
super.draw(printRect!)
}
}
func calculatePrintHeight() -> Float {
let pi = NSPrintOperation.current()!.printInfo
let paperSize = pi.paperSize
let pageHeight = Float(paperSize.height - pi.topMargin - pi.bottomMargin)
let scale = Float(pi.dictionary().object(forKey: NSPrintScalingFactor) as! CGFloat)
return pageHeight / scale
}
func calculatePrintWidth() -> Float {
let pi = NSPrintOperation.current()!.printInfo
let paperSize = pi.paperSize
let pageWidth = Float(paperSize.width - pi.leftMargin - pi.rightMargin)
let scale = Float(pi.dictionary().object(forKey: NSPrintScalingFactor) as! CGFloat)
return pageWidth / scale
}
override func knowsPageRange(_ range: NSRangePointer) -> Bool {
range.pointee.location = 1
range.pointee.length = 1
return true
}
override func rectForPage(_ page: Int) -> NSRect {
let bounds = self.bounds
let pageHeight = calculatePrintHeight()
let rect = NSMakeRect( NSMinX(bounds), NSMinY(bounds), frame.width, CGFloat(pageHeight));
return rect;
}
}
How to print NSCollectionView with all available content?
I am trying to exclusively display the points which I have data for on the x-axis. As shown in the example below, I only got data for point zero, but -1 and 1 are being displayed as well. How can I get rid of them?
func setChart(_ xValues: [String], yValuesLineChart: [Double], yValuesBarChart: [Double]) {
var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
var yVals2 : [BarChartDataEntry] = [BarChartDataEntry]()
for i in 0..<xValues.count {
yVals1.append(ChartDataEntry(x: Double(i), y: yValuesLineChart[i]))
yVals2.append(BarChartDataEntry(x: Double(i), y: yValuesBarChart[i]))
}
let lineChartSet = LineChartDataSet(values: yVals1, label: "")
let barChartSet: BarChartDataSet = BarChartDataSet(values: yVals2, label: "")
combinedChartView.drawBarShadowEnabled = false
let data = CombinedChartData()
data.barData = BarChartData(dataSet: barChartSet)
data.lineData = LineChartData(dataSet: lineChartSet)
combinedChartView.xAxis.granularityEnabled = true
combinedChartView.xAxis.granularity = 1.0
combinedChartView.xAxis.decimals = 0
combinedChartView.leftAxis.axisMinimum = 0
combinedChartView.rightAxis.axisMinimum = 0
combinedChartView.chartDescription?.text = ""
combinedChartView.drawGridBackgroundEnabled = false
combinedChartView.xAxis.labelPosition = .bottom
combinedChartView.leftAxis.drawGridLinesEnabled = false
combinedChartView.rightAxis.drawGridLinesEnabled = false
combinedChartView.xAxis.drawGridLinesEnabled = false
combinedChartView.leftAxis.drawZeroLineEnabled = false
combinedChartView.rightAxis.drawZeroLineEnabled = false
barChartSet.axisDependency = .right
lineChartSet.axisDependency = .left
combinedChartView.rightAxis.axisMaximum = barChartSet.yMax*1.4
combinedChartView.leftAxis.axisMaximum = lineChartSet.yMax*1.2
combinedChartView.data = data
combinedChartView.animate(xAxisDuration: 2.0, yAxisDuration: 2.0, easingOption: .easeInCubic)
}
Write an extension for your ViewController that will just display an empty string if you have no value.
extension YourChartViewController:IAxisValueFormatter {
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
if value == 0.0
return ""
} else {
return String(Int(value))
}
}
}