hayateasdf's blog

Unity,C#, javascript,C++,python,batなど

swift SpriteKit

行うこと

  • ボタン作成
  • touchesBeganでタッチ判定
  • アクション(animation)
  • 画面遷移

実装

  • 1 Scene1.swift作成
  • 2 Scene2.swift作成
  • 3 GameViewControllerの書き換え
import SpriteKit
import GameplayKit

// https://qiita.com/WorldDownTown/items/26c0ba39015f023523a8
extension UIColor {
    convenience init(hex: UInt, alpha: CGFloat = 1.0) {
        let red: CGFloat = CGFloat((hex & 0xFF0000) >> 16) / 255.0
        let green: CGFloat = CGFloat((hex & 0x00FF00) >> 8) / 255.0
        let blue: CGFloat = CGFloat(hex & 0x0000FF) / 255.0
        self.init(red: red, green: green, blue: blue, alpha: alpha)
    }
}

class Scene1: SKScene {
    
    override func didMove(to view: SKView) {
        // self.backgroundColor = UIColor.red
        self.backgroundColor = UIColor.white
        
        let button = self.createSquare("button")
        button.run(self.actionSequence(), completion: {
            self.transition()
        })
        self.addChild(button)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first as UITouch? {
            let location = touch.location(in: self)
            if self.atPoint(location).name == "button" {
                self.transition()
            }
        }
    }
    
    func transition() {
//        let transition = SKTransition.fade(withDuration: 2.0)
        let transition = SKTransition.push(with: .left, duration: 1.0)
        let scene = Scene2(size: self.view!.frame.size)
        self.view!.presentScene(scene, transition: transition)
    }
    
    // https://developer.apple.com/documentation/spritekit/skaction
    func action() -> SKAction {
        return SKAction.moveBy(x: 0, y: 100, duration: 1.0)
    }
    func actionSequence() -> SKAction {
        let moveUp = SKAction.moveBy(x: 0, y: 100, duration: 1.0)
        let zoom = SKAction.scale(to: 2.0, duration: 0.25)
        let wait = SKAction.wait(forDuration: 0.5)
        let fadeAway = SKAction.fadeOut(withDuration: 0.25)
        let removeNode = SKAction.removeFromParent()
        let sequence = SKAction.sequence(([moveUp, zoom, wait, fadeAway, removeNode]))
        
        return sequence
    }
    
    func createLabel(_ name: String) -> SKLabelNode {
        let label = SKLabelNode(fontNamed: "Chalkduster")
        label.text = "Hello World!"
        label.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
        label.fontSize = CGFloat(30)
        label.name = name
        
        return label
    }
    func createSquare(_ name: String) -> SKShapeNode {
        let square = SKShapeNode(rectOf: CGSize(width: 150, height: 100))
        square.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
        // square.fillColor = UIColor.blue
        square.fillColor = UIColor(hex: 0x008678)
        square.name = name
        
        return square
    }
}
import SpriteKit
import GameplayKit

class Scene2: SKScene {
    
    override func didMove(to view: SKView) {
        self.backgroundColor = UIColor.black
        
        let button = self.createSquare("button")
        button.run(self.action(), completion: {
          self.transition()
        })
        self.addChild(button)
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first as UITouch? {
            let location = touch.location(in: self)
            if self.atPoint(location).name == "button" {
                self.transition()
            }
        }
    }
    func createSquare(_ name: String) -> SKShapeNode {
        let square = SKShapeNode(rectOf: CGSize(width: 150, height: 100))
        square.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
        // square.fillColor = UIColor.red
        // http://www.geocities.jp/net_t3/color/tone-v.html
        square.fillColor = UIColor(hex: 0xee0026)
        square.strokeColor = UIColor.clear
        square.name = name
        
        return square
    }
    func transition() {
//        let transition = SKTransition.fade(withDuration: 2.0)
        let transition = SKTransition.push(with: .left, duration: 1.0)
        let scene = Scene1(size: self.view!.frame.size)
        self.view!.presentScene(scene, transition: transition)
    }
    func action() -> SKAction {
        return SKAction.moveBy(x: 0, y: 100, duration: 1.0)
    }
}
import UIKit
import SpriteKit
import GameplayKit

class GameViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let view = self.view as! SKView? {
            
            let scene = Scene1(size: view.frame.size)
            view.presentScene(scene)
            
            view.ignoresSiblingOrder = true
            view.showsFPS = true
            view.showsNodeCount = true
        }
    }

    override var shouldAutorotate: Bool {
        return true
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if UIDevice.current.userInterfaceIdiom == .phone {
            return .allButUpsideDown
        } else {
            return .all
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Release any cached data, images, etc that aren't in use.
    }

    override var prefersStatusBarHidden: Bool {
        return true
    }
}

swift WebView

WebViewでjsonを読み込み、値をWebViewに表示する

  • 1 ファイル WebViewJsonController作成 (UIViewController継承)
  • 2 ストーリーボード ViewControllerのアイデンティティアイコンを選択肢、classをWebViewJsonControllerに変更
  • 3 ストーリーボード WebViewをViewControllerに追加
  • 4 ストーリーボード Toolbar追加 (アイテムでback, next)
  • 5 ストーリーボード WebViewを選択肢し、右クリック押しっぱでコードにドラッグアンドドロップ outletでwebView
  • 6 ストーリーボード backボタンをコードへ actionでbackButton
  • 7 ストーリーボード nextボタンをコードへ actionでnextButton

これで見た目こんな感じになる。 f:id:hayateasdf:20171013175604p:plain

  • 8 コード 下記コードになるように編集
import UIKit
import Foundation

class WebViewJsonController: UIViewController, UIWebViewDelegate {

    @IBOutlet weak var webView: UIWebView!
    let initialUrl = URL(string: "https://www.google.co.jp")!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.webView.delegate = self
        
        // web_test(initialUrl)
        json_test()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    @IBAction func backButton(_ sender: UIBarButtonItem) {
        webView.goBack()
    }
    @IBAction func nextButton(_ sender: UIBarButtonItem) {
        webView.goForward()
    }
    func web_test(_ url: URL) {
        let req = URLRequest(url: url)
        self.webView.loadRequest(req)
    }
    func json_test() {
        let url = URL(string: "http://ip.jsontest.com")!
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) -> Void in
            if let error = error {
                print(error)
                return
            }
            
            do {
                let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
                if json.count > 0 {
                    if let item = json["ip"] as? String {
                        if let postWebView = self.webView {
                            let html: String = "<h1>ip: \(item)</h1>"
                            postWebView.loadHTMLString(html, baseURL: nil)
                        }
                        print(item)
                    }
                }
            } catch {
                print("JSON シリアライズ失敗!")
            }
        }
        task.resume()
    }

}
  • 9 ATS(App Transport Security)を無効化
    Info.plistを開くときに、「Open As → Souce Code」すると、XMLになるので、下記のコードを追加。
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

まず確認用でweb_test()のコメントを外し、json_test()をコメントにして、 クロームからjsontest.comにアクセス。 これでアクセスできれば、ATSの無効化に成功。

f:id:hayateasdf:20171013175616p:plain

その後、web_test()をコメントにし、json_test()のコメントを外して、 自分のipアドレスが表示されれば成功。

3日で勉強したxcode + swift殴り書き

結論: http://docs.fabo.io/swift/ 逆引き最強説。

セグエ

今のViewControllerから次のViewControllerへ遷移すること。 遷移する部分。

ナビゲーションコントローラー

メニューバーのEditor > Emmed > navigationControllerで追加 すると、セグエした後に、上にナビゲーションが追加される。

xcode ショートカット

Cmd + R run
Cmd + B build
Cmd + . stop

新規でviewControllerを作った際に、ついでにスクリプトファイルも作る方法

1 ストーリーボードを開き、右下のUIアイテムからView Controllerをドラッグ&ドロップ
2 backgroundをてきとうな色に変更。
3 Is Initial View Controllerにチェックを入れ、スタート画面にする。
4 メニュー > File > New > File > Cocoa Touch Class
Class: Scene1ViewController
Subclass of: UIViewController
に設定。
5 右上の?アイコンのとなりのアイコンをクリック > Custom class > Scene1ViewController
これでScene2ViewControllerファイルにUIをドラッグ&ドロップできるようになる。

UIアイテムをソースコードに追加した後に削除するとNSExceptionエラー

http://hajihaji-lemon.com/smartphone/swift/connection_inspector/

http://easyramble.com/nsunknownkeyexception-by-removing-outlet.html

swiftからobjective-cのコードを実行する。

http://tech.admax.ninja/2014/09/26/about-bridging-header/
表示用のラベルを追加し、
ViewControllerにoutletでドラッグ&ドロップ

メニュー > File > New > File > Cocoa Touch class
Class: Cat
sub class of: NSObject
Language: Objective-C

Bridging-Header作成のダイアログが出るのでCreate。
使用するObjective-Cをimport

// xxxxx-Bridging-header.h
#ifndef Bridging_Header_h
#define Bridging_Header_h

#import "Cat.h"

#endif
// Cat.h
#import <Fondation/Foudation.h>

@interface Cat : NSObject
@property (nonatomic, copy) NSString *name;
- (id)initWithName:(NSString *)name;
- (NSString *)greeting;
@end
// Cat.m
@implementation Cat
- (id)initwithName:(NSString *)name
{
    self = [super init];
    if (self) {
        self.name = name;
    }
    return self;
}
- (NSString *)greeting
{
    return [NSString stringWithFormat:@"Hello %@", self.name];
}
@end
// ViewController.swift
import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        let obj: Cat = Cat(name: "CAT!")
        label.text = obj.greeting()
    }
}

https://ics.media/entry/6439

// table list

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var table: UITableView!

    let fruits = ["りんご", "みかん", "ぶどう"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    // セルを作る
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
      let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath)
      cell.textLabel!.text = fruits[indexPath.row]
      return cell
    }
    // セルの数
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return fruits.count
    }
    // セルがタップされた時の処理
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("セル番号:\(indexPath.row) セルの内容:\(fruits[indexPath.row])")
    }
    // セルの高さを設定
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
      return 64
    }
}

コード書いてる時に思ったこ

あってる間違っているとか気にせず、とにかく書く

書いていけばあとからわかるから。

コードは折りたため!

https://teratail.com/questions/17569
クラス書いたらと折りたたむ。
ブレークポイントと折りたたみがかぶる問題が発生。
ブレークポイントを全削除する。

vimキーバインド設定がめんどくさそう

xcodeのフォルダをsublimetextにdrag & dropして
もはやsublimetextでキーバインドvim設定にして
sublimeで作業すればおk。

適当に機能を試したい

http://docs.fabo.io/swift/
逆引きから適当に追加していくだけで、なんとなくできあがる。

即時関数使うとコンパクトに見える

class ViewController {
    private var text_filed: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        print("View Controller2")
        
        // ココ!
        text_filed = {
            let w: CGFloat = 200
            let h: CGFloat = 50
            
            let rect = CGRect(
                x: (self.view.bounds.width - w) / 2,
                y: (self.view.bounds.height - h) / 2,
                width: w,
                height: h
            )
            
            return UITextField(frame: rect)
        }()

        // 表示するテキスト
        text_filed.text = "Hello TextField"
        // Delegateを自身に設定する
        text_filed.delegate = self
        // 枠を表示する
        text_filed.borderStyle = .roundedRect
        // クリアボタンを追加
        text_filed.clearButtonMode = .whileEditing
        
        // viewに追加
        self.view.addSubview(text_filed)
    }
}

Google Calendarから祝日を取得

環境

  • VS Code

  • Python 3.6.2

    • pip install

OAuth認証でGoogle Calendar APIに接続する(python 編)

quickstart.pyを実行し、カレンダー利用の許可。
このコードはholiday.pyにリネームする。

GoogleカレンダーAPIを使って、日本の祝日を取得する

コードの下記のAPI実行の部分を利用する。
holiday.pyに記述。

Pythonで「指定した年と月」の「すべての日付」を表示する関数をつくってみた

上記の方法で1年分のカレンダーを作成する。
新規でtest.py作成

holiday.py

from __future__ import print_function
import httplib2
import os

from apiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage

from datetime import date

try:
    import argparse
    flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
    flags = None

# If modifying these scopes, delete your previously saved credentials
# at ~/.credentials/calendar-python-quickstart.json
SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Google Calendar API Python Quickstart'


def _get_credentials():
    """Gets valid user credentials from storage.

    If nothing has been stored, or if the stored credentials are invalid,
    the OAuth2 flow is completed to obtain the new credentials.

    Returns:
        Credentials, the obtained credential.
    """
    home_dir = os.path.expanduser('~')
    credential_dir = os.path.join(home_dir, '.credentials')
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)
    credential_path = os.path.join(credential_dir,
                                   'calendar-python-quickstart.json')

    store = Storage(credential_path)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        if flags:
            credentials = tools.run_flow(flow, store, flags)
        else: # Needed only for compatibility with Python 2.6
            credentials = tools.run(flow, store)
        print('Storing credentials to ' + credential_path)
    return credentials

def get_holiday_events(year):
    """Shows basic usage of the Google Calendar API.

    Creates a Google Calendar API service object and outputs a list of the next
    10 events on the user's calendar.
    """
    credentials = _get_credentials()
    http = credentials.authorize(httplib2.Http())
    service = discovery.build('calendar', 'v3', http=http)

    calendar_id = 'ja.japanese#holiday@group.v.calendar.google.com'
    calendar_min = date(year=year, month=1, day=1).isoformat() + 'T00:00:00.000000Z'
    calendar_max = date(year=year, month=12, day=31).isoformat() + 'T00:00:00.000000Z'

    event_results = service.events().list(
      calendarId = calendar_id,
      timeMin = calendar_min,
      timeMax = calendar_max,
      maxResults = 50,
      singleEvents = True,
      orderBy = "startTime"
    ).execute()

    events = event_results.get('items', [])
    # for event in events:
    #   print("%s\t%s" % (event["start"]["date"], event["summary"]))
    
    return events;

test.py

import calendar
import holiday
from datetime import date

def get_year_days(year, month):
  month_days = [i+1 for i in range(calendar.monthrange(year, month)[1])]
  days = list(map(lambda day: "{0:02d}/{1:02d}/{2:02d}".format(year, month, day), month_days))
  return days

def main(year):
  months = [i+1 for i in range(12)]
  year_days = list(map(lambda month: get_year_days(year, month), months))

  events = holiday.get_holiday_events(year)
  holiday_dict = dict(
        (event["start"]["date"].replace("-", "/"), event["summary"])
        for event in events
      )

  for month in year_days:
    for day in month:
      if day in holiday_dict:
        print(day + " " + holiday_dict[day])
      else:
        print(day)

if __name__ == '__main__':
  main(2017)

結果

2017/01/01 元日
2017/01/02 元日 振替休日
2017/01/03
2017/01/04
2017/01/05
2017/01/06
2017/01/07
2017/01/08
2017/01/09 成人の日
2017/01/10
2017/01/11
2017/01/12
...
2017/12/23 天皇誕生日
2017/12/24
2017/12/25
2017/12/26
2017/12/27
2017/12/28
2017/12/29
2017/12/30
2017/12/31

css gridレイアウト 1.

参考

CSS Grid Layout を極める!(基礎編)
A Complete Guide to Grid

目的

  • display: grid;を使ってみる
  • grid-template-rows, grid-template-columnsでの画面サイズ設定
  • grid-template-areasでのgrid-area画面レイアウト

See the Pen CSS display:grid; 1 by tikyu (@tikyuu) on CodePen.