CustomGridTableViewController@GitHub
#GridTableを作成
【Swift】自由度の高いDataGridViewを作る
にて画面全体にグリッドを配置してたんですけど、このままだと全然簡単に使いまわせないです。
画面の指定した位置になるべく簡単にグリッドを配置出来るように修正したいと思います。
##未対応
・Swift2.0
・回転したときの再描画
・その他もろもろ機能不足
##修正方針
座標を指定して作成するようにしてもいいんですけど、僕がAutoLayoutを基本的に使うので、
1.とりあえずUIViewControllerからなるべくソースを減らす
2.配置したい場所にUIViewを配置
3.そこにテーブルを作成するように修正
という感じで出来るようにします。
・・・すいません、嘘です。修正かけて一発目の実行結果です。
まぁこんな感じになりますよね。
ViewControllerのViewにaddしたUIViewに、コントロールを配置するときもoriginを考慮して計算してました。
あとヘッダーラベルははみ出るときは載せないほうがまだいいですね。
とりあえず出来ました。
使い方は
###1.storyBoardでUIViewを配置
※わかりやすいように背景色を黒にしてます
###2.Outlet接続とメンバ変数にtableViewを
###3.viewDidLoadで初期化
delegateとかdatasourceの設定はこの中でしてます。
tableView.initSetting(self)
###4.viewDidLoadでColumnとデータを追加
tableView.cols.append(GridColumn().initWithPropertyName("id",headerText: "ID",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("name",headerText: "名前",width: 80))
tableView.cols.append(GridColumn().initWithPropertyName("1",headerText: "1",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("2",headerText: "2",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("3",headerText: "3",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("4",headerText: "4",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("5",headerText: "5",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("6",headerText: "6",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("7",headerText: "7",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("8",headerText: "8",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("9",headerText: "9",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("10",headerText: "10",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("11",headerText: "11",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("12",headerText: "12",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("13",headerText: "13",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("14",headerText: "14",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("15",headerText: "15",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("16",headerText: "16",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("17",headerText: "17",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("18",headerText: "18",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("19",headerText: "19",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("20",headerText: "20",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("21",headerText: "21",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("22",headerText: "22",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("23",headerText: "23",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("24",headerText: "24",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("25",headerText: "25",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("26",headerText: "26",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("27",headerText: "27",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("28",headerText: "28",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("29",headerText: "29",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("30",headerText: "30",width: tableView.calWidth))
tableView.cols.append(GridColumn().initWithPropertyName("31",headerText: "31",width: tableView.calWidth))
//sampleData
tableView.rows.append(["id":"1","name":"大工 智博","tel":"090-9999-9999","5":"○"])
tableView.rows.append(["id":"2","name":"山田 太郎","tel":"090-1234-5657","5":"○","6":"○","7":"○"])
tableView.rows.append(["id":"3","name":"山田 太郎","tel":"090-9999-9999"])
tableView.rows.append(["id":"4","name":"山田 太郎","tel":"090-9999-9999"])
tableView.rows.append(["id":"5","name":"山田 太郎","tel":"090-9999-9999"])
tableView.rows.append(["id":"6","name":"山田 太郎","tel":"090-9999-9999"])
tableView.rows.append(["id":"7","name":"山田 太郎","tel":"090-9999-9999"])
###5.viewDidLoadでColumnとデータを追加
//self.tableView.makeHeaderAndTableView(self,tableView: tableView) //全画面表示する場合
self.tableView.makeHeaderAndTableViewAutoLayout(self,tableView: tableView,drawSpaceView:view_CustomTableView)
###6.uitableView Delegateの作成
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return self.tableView.cellHeight
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.tableView.rows.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cellId: String = "GridViewCell:\(indexPath.section)"
var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier(cellId) as? UITableViewCell
if cell == nil {
var style: UITableViewCellStyle = UITableViewCellStyle.Default
cell = UITableViewCell(style: style, reuseIdentifier: cellId)
cell!.selectionStyle = UITableViewCellSelectionStyle.None
cell!.layoutMargins = UIEdgeInsetsZero
if indexPath.row % 2 == 1{
cell!.backgroundColor = self.tableView.EvenBackgroundColor
}else{
cell!.backgroundColor = UIColor.clearColor()
}
}
for view in cell!.contentView.subviews {
view.removeFromSuperview()
}
var row: Dictionary = self.tableView.rows[indexPath.row]
for var i = 0; i < self.tableView.cols.count; i++ {
var col: GridColumn = self.tableView.cols[i]
var left: Int = self.tableView.getLeftPosition(i)
let leftAdd:CGFloat = CGFloat(left + 5)
var label: UILabel = UILabel(frame: CGRectMake(CGFloat(left + 1), 0, CGFloat(col.width! - 1), self.tableView.cellHeight))
if let str = row[col.propertyName!]{
label.text = str
}
label.tag = i + (indexPath.row * 1000)
label.textAlignment = NSTextAlignment.Center
label.backgroundColor = UIColor.clearColor()
label.font = UIFont.systemFontOfSize(14)
label.textColor = UIColor.darkGrayColor()
cell!.contentView.addSubview(label)
if(CustomUITableView.getCellTouchedFlg(label.tag)){
CustomUITableView.tableTouchDelegateShowOnly(label)
}
}
return cell!
}
cellの設定部分がすごく煩雑ですね。
そのうちCustomUITableViewに処理を写して臭いものにフタをしたいと思います。
###7.CustomUITableView.swiftをプロジェクトに配置
こっちのほうが最初の作業ですよね・・・
まぁいっか。
//
// GridColumn.swift
// DataGridView
//
// Created by 大工智博 on 2015/08/28.
// Copyright (c) 2015年 medikaruno. All rights reserved.
//
import Foundation
import UIKit
class GridColumn : NSObject{
var width:Int?
var propertyName:String?
var headerText:String?
var isTouched:Bool = false
func initWithPropertyName(propertyName: String, headerText: String, width: Int) -> GridColumn {
self.propertyName = propertyName
self.headerText = headerText
self.width = width
return self
}
}
enum SelectMode{
case None
case On
case On2
case Off
case Off2
case OnOff
case TextInsert
case TextDelete
}
class CustomUITableView:UITableView{
static let STATES_BAR_HEIGHT: CGFloat = UIApplication.sharedApplication().statusBarFrame.height
static var staticTableView: UITableView = CustomUITableView()
static var staticCols:Array<GridColumn> = Array()
static var touchBeganCol:Int = 0
static var isTouched:Dictionary<String,Bool> = Dictionary()
static var preCellIndexAtMoving = -1
static var touchOffColIndex = 1
static var selectMode:SelectMode = SelectMode.None
var headerView: UIView = UIView()
var cols:Array<GridColumn> = Array()
var rows:Array<Dictionary<String,String>> = Array()//Dictionary<String,AnyObject>()
/**
カスタマイズ項目
oddBackgroundColor:奇数行の背景色
headerHeihgt:ヘッダーの高さ
cellHeight:Cellの高さ
tableTouchDelegateShowOnly(UILabel):セルをオンにした時にセルに対する変更を記述
tableTouchOnDelegate(UILabel,UITouch):セルをオンにした時にデータに対する変更を記述
*/
var EvenBackgroundColor:UIColor = UIColor(red: 0, green: 0, blue: 50, alpha: 0.1)
var headerHeihgt:CGFloat = 40
var cellHeight:CGFloat = 40
var calWidth:Int = 30
func initSetting(view:UIViewController){
self.autoresizingMask = UIViewAutoresizing.FlexibleHeight //UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth
self.delegate = view as? UITableViewDelegate
self.dataSource = view as? UITableViewDataSource
self.allowsSelection = true
self.userInteractionEnabled = true
self.layoutMargins = UIEdgeInsetsZero
self.separatorInset = UIEdgeInsetsZero;
//self.scrollEnabled = false
}
/*
設定されたColを元にヘッダーとTableViewを作成する
*/
func makeHeaderAndTableView(uiViewController:UIViewController,tableView:CustomUITableView) {
var totalHeaderHeight = headerHeihgt + CustomUITableView.STATES_BAR_HEIGHT
self.headerView.autoresizingMask = UIViewAutoresizing.FlexibleWidth
self.headerView.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
var headerFrame: CGRect = CGRectMake(0, 0, uiViewController.view.bounds.size.width, totalHeaderHeight)
self.headerView.frame = headerFrame
uiViewController.view.addSubview(self.headerView)
var separatorTop: UIView = UIView(frame: CGRectMake(0, CustomUITableView.STATES_BAR_HEIGHT, CGFloat(self.headerView.bounds.size.width),1 ))
separatorTop.backgroundColor = UIColor.lightGrayColor()
uiViewController.view.addSubview(separatorTop)
for var i = 0; i < self.cols.count; i++ {
var col: GridColumn = self.cols[i]
var left: Int = self.getLeftPosition(i)
var label: UILabel = UILabel(frame: CGRectMake(CGFloat(left + 1), CustomUITableView.STATES_BAR_HEIGHT, CGFloat(col.width! - 1), headerHeihgt))
if let str = col.headerText{
label.text = str
}
label.textAlignment = NSTextAlignment.Center
label.backgroundColor = UIColor.clearColor()
label.font = UIFont.systemFontOfSize(14)
label.textColor = UIColor.darkGrayColor()
self.headerView.addSubview(label)
var right: Int = self.getLeftPosition(i + 1)
var separator: UIView = UIView(frame: CGRectMake(CGFloat(right), CustomUITableView.STATES_BAR_HEIGHT, 1, CGFloat(self.headerView.bounds.size.height)))
separator.backgroundColor = UIColor.lightGrayColor()
self.headerView.addSubview(separator)
}
var bottomBorder: UIView = UIView(frame: CGRectMake(0, totalHeaderHeight - 1, self.headerView.bounds.size.width, 1))
bottomBorder.autoresizingMask = UIViewAutoresizing.FlexibleWidth
bottomBorder.backgroundColor = UIColor.lightGrayColor()
self.headerView.addSubview(bottomBorder)
var tableFrame: CGRect = CGRectMake(0, totalHeaderHeight, uiViewController.view.bounds.size.width, uiViewController.view.bounds.size.height)
tableView.frame = tableFrame
uiViewController.view.addSubview(tableView)
var bgView: UIView = UIView(frame: tableView.frame)
bgView.backgroundColor = UIColor.whiteColor()
tableView.backgroundView = bgView
for var i = 0; i < cols.count; i++ {
var right: Int = tableView.getLeftPosition(i + 1)
var tableSeparator: UIView = UIView(frame: CGRectMake(CGFloat(right), 0, 1, CGFloat(tableView.bounds.size.height)))
if(i % 7 == CustomUITableView.touchOffColIndex){tableSeparator.backgroundColor = UIColor.yellowColor()
}else{tableSeparator.backgroundColor = UIColor.lightGrayColor()}
tableView.backgroundView!.addSubview(tableSeparator)
}
CustomUITableView.staticTableView = tableView
CustomUITableView.staticCols = cols
}
/*
設定されたColを元にAutoLayoutで設定しているヘッダーとTableViewを作成する
*/
func makeHeaderAndTableViewAutoLayout(uiViewController:UIViewController,tableView:CustomUITableView,drawSpaceView:UIView) {
//全画面じゃない場合はborder追加
self.layer.borderColor = UIColor.grayColor().CGColor
self.layer.borderWidth = 1
let x = drawSpaceView.frame.origin.x
let y = drawSpaceView.frame.origin.y
let width = drawSpaceView.bounds.size.width
let allHeight = drawSpaceView.bounds.size.height
self.headerView.autoresizingMask = UIViewAutoresizing.FlexibleWidth
self.headerView.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
var headerFrame: CGRect = CGRectMake(x, y ,width, headerHeihgt)
self.headerView.frame = headerFrame
uiViewController.view.addSubview(self.headerView)
var separatorTop: UIView = UIView(frame: CGRectMake(x, y, CGFloat(width),1 ))
separatorTop.backgroundColor = UIColor.lightGrayColor()
uiViewController.view.addSubview(separatorTop)
for var i = 0; i < self.cols.count; i++ {
var col: GridColumn = self.cols[i]
var left: Int = self.getLeftPosition(i)
if(left + col.width!) > Int(width){break}
var label: UILabel = UILabel(frame: CGRectMake(CGFloat(left + 1), 0, CGFloat(col.width! - 1), headerHeihgt))
if let str = col.headerText{
label.text = str
}
label.textAlignment = NSTextAlignment.Center
label.backgroundColor = UIColor.clearColor()
label.font = UIFont.systemFontOfSize(14)
label.textColor = UIColor.darkGrayColor()
self.headerView.addSubview(label)
var right: Int = self.getLeftPosition(i + 1)
var separator: UIView = UIView(frame: CGRectMake(CGFloat(right), 0, 1, CGFloat(headerHeihgt)))
separator.backgroundColor = UIColor.lightGrayColor()
self.headerView.addSubview(separator)
}
var leftBorder: UIView = UIView(frame: CGRectMake(0, 0, 1, headerHeihgt))
leftBorder.autoresizingMask = UIViewAutoresizing.FlexibleWidth
leftBorder.backgroundColor = UIColor.lightGrayColor()
self.headerView.addSubview(leftBorder)
var rightBorder: UIView = UIView(frame: CGRectMake(width - 1, 0, 1, headerHeihgt))
rightBorder.autoresizingMask = UIViewAutoresizing.FlexibleWidth
rightBorder.backgroundColor = UIColor.lightGrayColor()
self.headerView.addSubview(rightBorder)
var tableFrame: CGRect = CGRectMake(x, y + headerHeihgt, width, allHeight - headerHeihgt)
tableView.frame = tableFrame
uiViewController.view.addSubview(tableView)
var bgView: UIView = UIView(frame: tableView.frame)
bgView.backgroundColor = UIColor.whiteColor()
tableView.backgroundView = bgView
for var i = 0; i < cols.count; i++ {
var right: Int = tableView.getLeftPosition(i + 1)
var tableSeparator: UIView = UIView(frame: CGRectMake(CGFloat(right), 0, 1, CGFloat(allHeight - headerHeihgt)))
//if(i % 7 == CustomUITableView.touchOffColIndex){tableSeparator.backgroundColor = UIColor.yellowColor()
//}else{tableSeparator.backgroundColor = UIColor.lightGrayColor()}
tableSeparator.backgroundColor = UIColor.lightGrayColor()
tableView.backgroundView!.addSubview(tableSeparator)
}
CustomUITableView.staticTableView = tableView
CustomUITableView.staticCols = cols
}
// 列の左端の座標を取得
func getLeftPosition(colNumber:Int) -> Int {
var x:Int = 0
for (var i = 0; i < self.cols.count; i++) { //TODO: width:-1で可変幅列
var col:GridColumn = self.cols[i]
if (i == colNumber) {
return x
}
x += col.width!
} // その他の場合は、length+1として受け付ける
return x
}
static var tableTouchOnDelegate:(UILabel,UITouch) -> () = {(touchedLabel:UILabel,touch:UITouch) -> () in
tableTouchDelegateShowOnly(touchedLabel)
}
static var tableTouchOffDelegate:(UILabel,UITouch) -> () = {(touchedLabel:UILabel,touch:UITouch) -> () in
touchedLabel.backgroundColor = UIColor.clearColor()
}
static var tableTouchDelegateShowOnly:(UILabel) -> () = {(touchedLabel:UILabel) -> () in
touchedLabel.backgroundColor = UIColor.redColor()
}
static var tableViewTouchBegan:(UITouch) -> () = {(touch:UITouch) -> () in
CustomUITableView.touchTableViewDelegate(touch)
}
static var tableViewTouchMove:(UITouch) -> () = {(touch:UITouch) -> () in
CustomUITableView.touchmoveTableViewDelegate(touch)
}
static var tableViewTouchEnd:(UITouch) -> () = {(touch:UITouch) -> () in
//CustomGridTableViewController.touchendTableViewDelegate(touch)
}
static func touchTableViewDelegate(touch:UITouch){
let location = touch.locationInView(CustomUITableView.staticTableView)
if let indexPath = CustomUITableView.staticTableView.indexPathForRowAtPoint(location){
println(indexPath.row)
var touchCol:Int = CustomUITableView.getColumnIndex(Int(location.x))
if touchCol <= touchOffColIndex {return} //タッチ無効インデックス以下の場合は処理中止
touchBeganCol = touchCol
preCellIndexAtMoving = touchCol //moveイベントに入った時にtouchで処理したセルを処理しないようにする
if let label = CustomUITableView.staticTableView.viewWithTag(touchCol + (indexPath.row * 1000)) as? UILabel{
changeCellTouchedFlg(touchCol + (indexPath.row * 1000))
if(CustomUITableView.getCellTouchedFlg(touchCol + (indexPath.row * 1000))){
CustomUITableView.tableTouchOnDelegate(label,touch)
}else{
CustomUITableView.tableTouchOffDelegate(label,touch)
}
}
}
}
static func touchmoveTableViewDelegate(touch:UITouch){
let location = touch.locationInView(CustomUITableView.staticTableView)
if let indexPath = CustomUITableView.staticTableView.indexPathForRowAtPoint(location){
println(indexPath.row)
var touchMovingCol:Int = CustomUITableView.getColumnIndex(Int(location.x))
if touchMovingCol <= touchOffColIndex {return} //タッチ無効インデックス以下の場合は処理中止
if preCellIndexAtMoving == touchMovingCol {return} //前回と同じセルの場合は処理しない
preCellIndexAtMoving = touchMovingCol
if let label = CustomUITableView.staticTableView.viewWithTag(touchMovingCol + (indexPath.row * 1000)) as? UILabel{
changeCellTouchedFlg(touchMovingCol + (indexPath.row * 1000))
if(CustomUITableView.getCellTouchedFlg(touchMovingCol + (indexPath.row * 1000))){
CustomUITableView.tableTouchOnDelegate(label,touch)
}else{
tableTouchOffDelegate(label,touch)
}
}
}
}
/**
セルの特定データがタッチされているかモードによってフラグを管理する
SelectMode.On:タッチされたらTrue
SelectMode.Off:タッチされたらFalse
SelectMode.OnOff:タッチされたらTrue、Falseを切り替える
SelectModeそれ以外:TODO
*/
static func changeCellTouchedFlg(searchTag:Int){
if selectMode == SelectMode.On{
CustomUITableView.isTouched[searchTag.description] = true
return
}else if selectMode == SelectMode.Off{
CustomUITableView.isTouched[searchTag.description] = false
return
}else if selectMode == SelectMode.None{
return
}
if let existTagVal = CustomUITableView.isTouched[searchTag.description]{
if(existTagVal == true){
CustomUITableView.isTouched[searchTag.description] = false
}else{
CustomUITableView.isTouched[searchTag.description] = true
}
}else{
CustomUITableView.isTouched[searchTag.description] = true
}
}
// 列のインデックスを取得
static func getColumnIndex(widthPosition:Int) -> Int {
var x:Int = 0
for (var i = 0; i < CustomUITableView.staticCols.count; i++) { //TODO: width:-1で可変幅列
var col:GridColumn = CustomUITableView.staticCols[i]
if (widthPosition <= x) {
return i - 1
}
x += col.width!
} // その他の場合は、length+1として受け付ける
return CustomUITableView.staticCols.count - 1
}
/**
セルの特定データがタッチされているかどうか
*/
static func getCellTouchedFlg(searchTag:Int) -> Bool{
if let existTagVal = CustomUITableView.isTouched[searchTag.description]{
return existTagVal
}else{
return false
}
}
/**
touchesBeganイベント
*/
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
// タッチイベントを取得.
let touch = touches.first as! UITouch
CustomUITableView.tableViewTouchBegan(touch)
}
/**
touchesEndedイベント
*/
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
CustomUITableView.tableViewTouchEnd(touch)
}
/**
touchesMovedイベント
*/
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
CustomUITableView.tableViewTouchMove(touch)
}
}