Swift将代码转换为组件以供多次使用

时间:2016-06-10 21:07:41

标签: xcode swift

我是一个Swift新手,我试图获得一些感觉应该很容易的东西但是我缺乏对Storyboard + Swift +术语的了解让我退缩了!

我想创建一个水平滚动组件,它实现了以下设计目标:

  • 我可以使用几行代码轻松将其添加到我的应用中的任何视图
  • 我可以传入一组值来配置滚动条中的每个元素
  • 滚动条元素(单元格?)是在.xib文件中设计的
  • 我可以在任何视图中有多个滚动条实例

我创建了一个简单的示例滚动条,它具有以下结构:

  • ViewController(Horizo​​ntalScrollerVC.swift)
  • 故事板(用于创建插座,约束和一些配置)
  • UICollectionViewCell子类(MyCell.swift)
  • 自定义xib文件,其中Class属性设置为MyCell.swift(MyCell.xib)

我想这个组件可能会在ViewController的viewDidLoad()方法中使用,如下所示:

//**Pseudo code**

let data1 = ["a","b","c"]
let data2 = ["1","2","3"]

let scroller1:MyScroller = ScrollerFromData(data:data1)
scroller1.constraints = somePositioningConstraints
view.add(scroller1)

let scroller2:MyScroller = ScrollerFromDataWithCellType(data:data2,cellType:"MyCell2")
scroller2.constraints = someDifferentPositioningConstraints
view.add(scroller2)

如何将我的代码/结构转换为我可以按上述方式使用的内容的任何建议都会很棒。

代码

Horizo​​ntalScrollerVC.swift

import UIKit

class HorizontalScrollerVC: UIViewController {

    // set up some data
    let dataArray = ["Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet"]

    // create an outlet to communicate with the collectionView
    @IBOutlet weak var myCollectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let cellNib = UINib(nibName: "MyCell", bundle: nil)
        self.myCollectionView.registerNib(cellNib, forCellWithReuseIdentifier: "MyCell")
        self.myCollectionView.backgroundColor = UIColor.init(colorLiteralRed: 0.9, green: 0.6, blue: 0.9, alpha: 1.0)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: CollectionView methods
    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return dataArray.count
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MyCell", forIndexPath: indexPath) as! MyCell
        self.configureCell(cell, forIndexPath: indexPath)
        return cell
    }

    func configureCell(cell: MyCell, forIndexPath indexPath: NSIndexPath) {
        let cellTitle = dataArray[indexPath.row]
        cell.cellTitle.text = cellTitle
    }
}

MyCell.swift

import UIKit

class MyCell: UICollectionViewCell {

    @IBOutlet weak var cellTitle: UILabel!

    override func awakeFromNib() {
        self.backgroundColor = UIColor.init(colorLiteralRed: 0.95, green: 0.95, blue: 0.95, alpha: 1.0)
        self.cellTitle.textColor = UIColor.darkGrayColor()
        self.layer.cornerRadius = 5
    }
}

MyCell.xib 非常简单,但有帮助,这里是xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="MyCell" customModule="testola" customModuleProvider="target">
            <rect key="frame" x="0.0" y="0.0" width="210" height="140"/>
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
            <subviews>
                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="4" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="h9Q-Ha-ZnF">
                    <rect key="frame" x="8" y="8" width="118" height="64"/>
                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                    <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
                    <nil key="highlightedColor"/>
                </label>
            </subviews>
            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
            <constraints>
                <constraint firstItem="h9Q-Ha-ZnF" firstAttribute="trailing" secondItem="iN0-l3-epB" secondAttribute="trailingMargin" constant="-76" id="S2o-eE-CYh"/>
                <constraint firstAttribute="bottomMargin" secondItem="h9Q-Ha-ZnF" secondAttribute="bottom" constant="60" id="U0s-fw-Rfv"/>
                <constraint firstItem="h9Q-Ha-ZnF" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leadingMargin" id="rwe-wi-Vff"/>
                <constraint firstItem="h9Q-Ha-ZnF" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="topMargin" id="sl1-pT-fj7"/>
            </constraints>
            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
            <connections>
                <outlet property="cellTitle" destination="h9Q-Ha-ZnF" id="8E8-HL-BCx"/>
            </connections>
            <point key="canvasLocation" x="195" y="139"/>
        </view>
    </objects>
</document>

这里是故事板 xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="49e-Tb-3d3">
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
    </dependencies>
    <scenes>
        <!--First-->
        <scene sceneID="hNz-n2-bh7">
            <objects>
                <viewController id="9pv-A4-QxB" customClass="HorizontalScrollerVC" customModule="testola" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="Ia1-K6-d13"/>
                        <viewControllerLayoutGuide type="bottom" id="4ug-Mw-9AY"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="tsR-hK-woN">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="ZD4-S1-Vkm">
                                <rect key="frame" x="-4" y="40" width="383" height="150"/>
                                <constraints>
                                    <constraint firstAttribute="height" constant="150" id="f2E-DB-ecy"/>
                                </constraints>
                                <collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="AYp-cr-c33">
                                    <size key="itemSize" width="210" height="140"/>
                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
                                    <inset key="sectionInset" minX="10" minY="0.0" maxX="10" maxY="0.0"/>
                                </collectionViewFlowLayout>
                                <cells>
                                    <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="zbW-CO-LP9">
                                        <rect key="frame" x="10" y="-20" width="210" height="140"/>
                                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                        <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
                                            <rect key="frame" x="0.0" y="0.0" width="210" height="140"/>
                                            <autoresizingMask key="autoresizingMask"/>
                                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                                        </view>
                                        <size key="customSize" width="210" height="140"/>
                                    </collectionViewCell>
                                </cells>
                                <connections>
                                    <outlet property="dataSource" destination="9pv-A4-QxB" id="p0g-qN-oUd"/>
                                    <outlet property="delegate" destination="9pv-A4-QxB" id="U7n-os-ldT"/>
                                </connections>
                            </collectionView>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="ZD4-S1-Vkm" firstAttribute="top" secondItem="Ia1-K6-d13" secondAttribute="bottom" constant="20" id="0Eh-uz-aT3"/>
                            <constraint firstAttribute="trailingMargin" secondItem="ZD4-S1-Vkm" secondAttribute="trailing" constant="-20" id="2wl-8R-h8o"/>
                            <constraint firstItem="ZD4-S1-Vkm" firstAttribute="leading" secondItem="tsR-hK-woN" secondAttribute="leadingMargin" constant="-20" id="XxF-oY-0Bo"/>
                        </constraints>
                    </view>
                    <tabBarItem key="tabBarItem" title="First" image="first" id="acW-dT-cKf"/>
                    <simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina47"/>
                    <connections>
                        <outlet property="myCollectionView" destination="ZD4-S1-Vkm" id="xWz-Uu-tsB"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="W5J-7L-Pyd" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="749.5" y="-320.5"/>
        </scene>
        <!--Second-->
        <scene sceneID="wg7-f3-ORb">
            <objects>
                <viewController id="8rJ-Kc-sve" customClass="SecondViewController" customModule="testola" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="L7p-HK-0SC"/>
                        <viewControllerLayoutGuide type="bottom" id="Djb-ko-YwX"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="QS5-Rx-YEW">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" text="Second View" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="zEq-FU-wV5">
                                <rect key="frame" x="83" y="313" width="210" height="42"/>
                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                <fontDescription key="fontDescription" name="Helvetica" family="Helvetica" pointSize="36"/>
                                <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
                                <nil key="highlightedColor"/>
                            </label>
                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Loaded by SecondViewController" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NDk-cv-Gan">
                                <rect key="frame" x="81" y="363" width="215" height="17"/>
                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="NDk-cv-Gan" firstAttribute="top" secondItem="zEq-FU-wV5" secondAttribute="bottom" constant="8" symbolic="YES" id="Day-4N-Vmt"/>
                            <constraint firstItem="NDk-cv-Gan" firstAttribute="centerX" secondItem="zEq-FU-wV5" secondAttribute="centerX" id="JgO-Fn-dHn"/>
                            <constraint firstAttribute="centerX" secondItem="zEq-FU-wV5" secondAttribute="centerX" id="qqM-NS-xev"/>
                            <constraint firstAttribute="centerY" secondItem="zEq-FU-wV5" secondAttribute="centerY" id="qzY-Ky-pLD"/>
                        </constraints>
                    </view>
                    <tabBarItem key="tabBarItem" title="Second" image="second" id="cPa-gy-q4n"/>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="4Nw-L8-lE0" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="750" y="360"/>
        </scene>
        <!--Tab Bar Controller-->
        <scene sceneID="yl2-sM-qoP">
            <objects>
                <tabBarController id="49e-Tb-3d3" sceneMemberID="viewController">
                    <nil key="simulatedBottomBarMetrics"/>
                    <simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina47"/>
                    <tabBar key="tabBar" contentMode="scaleToFill" id="W28-zg-YXA">
                        <rect key="frame" x="0.0" y="975" width="768" height="49"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                    </tabBar>
                    <connections>
                        <segue destination="9pv-A4-QxB" kind="relationship" relationship="viewControllers" id="u7Y-xg-7CH"/>
                        <segue destination="8rJ-Kc-sve" kind="relationship" relationship="viewControllers" id="lzU-1b-eKA"/>
                    </connections>
                </tabBarController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="HuB-VB-40B" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="0.0" y="0.0"/>
        </scene>
    </scenes>
    <resources>
        <image name="first" width="30" height="30"/>
        <image name="second" width="30" height="30"/>
    </resources>
</document>

2 个答案:

答案 0 :(得分:2)

之前我做过一些自定义控件。我过去所做的是从UIView创建一个子类。然后使用IBDesignable我可以开始为我的控件编写代码,并在编码时显示在Storyboard中。完成后,只需将UIView拖放到Storyboard,然后将类更改为您刚刚创建的自定义类。由于它将是一个IBDesignable注释类,您将能够在屏幕上看到它作为您的控件,而不仅仅是一个简单的UIView。将自定义控件放在Storyboard中后,还可以使用自动布局来定义其他内容,例如控件的宽度等。

您提到将数据传递给视图控制器。我在我的项目中使用了类似的东西。

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if let feed = segue.destinationViewController as? FeedTableViewController
            where segue.identifier == "EmbedFeed" {
            feed.yourVariable = [1,2,3]
        }
    }

答案 1 :(得分:0)

我有一个解决方案,所以我认为我发布简单的代码,以防任何像我这样的新手发现这篇文章(它是非常基本的东西)。

逻辑是:

  1. 创建一个新的Swift项目
  2. 创建自定义子类new - &gt; Cocoa Touch Class - &gt; Subclass of UIViewController AND check the同时创建XIB文件框
  3. 在主视图的UIView上创建一个IBOutlet
  4. 在您在步骤2中创建的Xib中创建自定义用户界面
  5. 将任何插座添加到您的自定义xib(我创建了一个标签以检查它是否有效)
  6. 在您的主VC中:
    1. 创建子类的实例(在步骤2中创建)(let myCustomWidget = CustomViewController(nibName: "CustomViewController", bundle: nil)
    2. 使用self.addChildViewController(myCustomWidget)
    3. 将实例添加到主视图控制器
    4. 将新实例添加到视图中,以便我们可以看到它self.masterView.addSubview(myScroller.view)
    5. 将数据发送到myCustomWidget实例并根据需要进行配置
  7. 一个简单的例子

    我们最终得到了什么(A&#39;主要&#39;视图,其中添加了几个自定义类实例作为子视图):

    Screenshot

    这是xcode的样子: Xcode screenshot

    FirstViewController.swift (&#39; master&#39; ViewController)

    import UIKit
    
    class FirstViewController: UIViewController {
    
        // create this outlet by ctrl+dragging in Storyboard's Assistant view
        @IBOutlet var firstView: UIView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // instantiate as many custom VCs as you want (I have a .xib called "ScrollerViewController.xib")
            let myScroller = ScrollerViewController(nibName: "ScrollerViewController", bundle: nil)
            let myScroller2 = ScrollerViewController(nibName: "ScrollerViewController", bundle: nil)
    
            // add the custom VC to the current VC
            self.addChildViewController(myScroller)
            // add the custom VC's view to the current VC's view (set via IBOutlet above)
            self.firstView.addSubview(myScroller.view)
    
            // ...do it again for the 2nd custom VC
            self.addChildViewController(myScroller2)
            self.firstView.addSubview(myScroller2.view)
    
            // move 2 so we can see it (use constraints in production)
            myScroller2.view.frame = CGRectOffset(myScroller2.view.frame, 0, 150);
    
            // Set up some data
            let dummyData = ["Wotcha!","Hello there"]
    
            // Pass the data to each instance of the custom VC
            // Note: this has to be done AFTER we've added it to the 'master' view
            myScroller.myTitle.text = dummyData[0]
            myScroller2.myTitle.text = dummyData[1]
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    }
    

    <强> ScrollerViewController.swift

    import UIKit
    
    class ScrollerViewController: UIViewController {
    
        // create an outlet to show that the passed in data works
        @IBOutlet var myTitle: UILabel!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
    }