あたも技術ブログ

セットジャパンコーポレーションの社員が運営しています。

CocoaPodsでライブラリを公開する

プロジェクトを作成

まずはライブラリを作るためにプロジェクトを作成します。

XcodeでCreate new projectしてもいいのですが、CocoaPodsがテンプレートを公開しており、ターミナルから作成できるので今回はターミナルから作成していきます。

プロジェクト作成

以下のコマンドをターミナルで実行するとカレントディレクトリにプロジェクトが作成されます。

途中、幾つかの質問があるので、回答していきます。

pod lib create ライブラリ名

質問1 使用する言語はどちらですか?

What language do you want to use?? [ ObjC / Swift ]
> ObjC or Swift で回答

質問2 デモアプリを同梱しますか?

Would you like to include a demo application with your library? [ Yes / No ]
> Yes or No で回答

質問3 テストフレームワークを使いますか?

Which testing frameworks will you use? [ Quick / None ]
> Quick or None(使わない) で回答

質問4 Viewのテストを行いますか?

Would you like to do view based testing? [ Yes / No ]
> Yes or No で回答

成功するとXcodeが起動し、作成したプロジェクトが開きます。

ライブラリの作成

開いたプロジェクト内ソースツリーの[Pods]->[Development Pods]->[ライブラリ名]->[ライブラリ名]->[Classes]ReplaceMeというファイルがあるので、削除して自作ライブラリのファイルを配置します。

GitHubで公開

ライブラリのGitHubページを作成し、リポジトリのURLをコピーしておきます。

https://github.com/ユーザ名/ライブラリ名.git

プロジェクトファイル内のライブラリ名.podspecを編集します。

s.source: コピーしたリポジトリのURL

s.summary: 短い説明

s.description: 長い説明

#
# Be sure to run `pod lib lint ライブラリ名.podspec' to ensure this is a
# valid spec before submitting.
#
# Any lines starting with a # are optional, but their use is encouraged
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#

Pod::Spec.new do |s|
  s.name             = 'ライブラリ名'
  s.version          = '0.1.0'
  s.summary          = 'A short description of ライブラリ名.'

# This description is used to generate tags and improve search results.
#   * Think: What does it do? Why did you write it? What is the focus?
#   * Try to keep it short, snappy and to the point.
#   * Write the description between the DESC delimiters below.
#   * Finally, don't worry about the indent, CocoaPods strips it!

  s.description      = <<-DESC
TODO: Add long description of the pod here.
                       DESC

  s.homepage         = 'https://github.com/ユーザ名/ライブラリ名'
  # s.screenshots     = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'ユーザ名' => 'メールアドレス' }
  s.source           = { :git => 'https://github.com/ユーザ名/ライブラリ名.git', :tag => s.version.to_s }
  # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'

  s.ios.deployment_target = '8.0'

  s.source_files = 'ライブラリ名/Classes/**/*'
  
  # s.resource_bundles = {
  #   'ライブラリ名' => ['ライブラリ名/Assets/*.png']
  # }

  # s.public_header_files = 'Pod/Classes/**/*.h'
  # s.frameworks = 'UIKit', 'MapKit'
  # s.dependency 'AFNetworking', '~> 2.3'
end

編集後、GitHubリポジトリにPushします。

Xcode上からSource Controlブランチ名Configure ライブラリ名を開き、RemoteからGitHubリポジトリを追加します。

Source ControlCommitを選択し、左下のPush to remoteへチェックを入れたらCommit Filesを押下します。

バージョンの指定

CocoaPods上でのバージョンはGitのタグに対応するので、ターミナルから公開時のバージョンをタグで付けます

git tag 1.0.0

リモートに反映します

git push 1.0.0

確認

podspecに誤りがないか確認します。

ターミナルでプロジェクトのディレクトリへ移動し、以下のコマンドを実行します。

pod lib lint

エラー場表示される場合は修正します。

(僕は説明が短すぎると言うエラーが出ました

CocoaPods trunkへ登録する

ターミナルでコマンドを実行します

pod trunk register 公開するメール '公開する名前' --description='説明'

入力したメールアドレスへ確認メールが来るので記載されているリンクを押下します。

ターミナル上で以下のコマンドを実行して名前が表示されていれば登録が完了しています。

pod trunk me

CocoaPods trunkへ登録します。

以下のコマンドを実行

pod trunk push ライブラリ名.podspec

pod try ライブラリ名 を実行してサンプルプロジェクトが開けば登録できています。

商用フリー 和柄パターン素材

 

f:id:atamo_dev:20170701161927p:plain

個人的に作成した和柄模様の素材です。

 

素材ファイルは下記URLに配置してあります。

https://drive.google.com/drive/folders/0B9dZ314mf8WoVGxla3hXeEVBSGc?usp=sharing

再配布以外でしたら個人用途に限りご自由にお使いください。

報告も、配布元の表示も不要です。

 

各素材とも下記2種類ずつあるので用途別にお使いいただければと思います。

Illustratorスウォッチ登録用aiファイル

Photoshopのパターン定義用にpngファイル

 

By SetJapanCorporation,Inc. Designer : すんすん。

【NW】名前解決って、なに?

「名前解決」・・・不思議な言葉ですよね。
この言葉ですぐわかる人は業界の人だけでしょう
ここでいう「名前」はインターネットURL、「解決」はIPアドレス検索、でしょうか
言い換えれば「インターネットURLからサーバのIPアドレスをさがす」イメージです。

皆さんがWebサイトなど見るときよくあるパターンは・・・
インターネットURLがLINEで来たり、QRコード読んだりして、
ブラウザでWebサイト見たりします
でも、見たいWebサイトが世界のどこにあるかは知りません。

Webサイトを公開するひとは、作ったら、どこかのWebサーバに格納します。
そして、このサーバはIPアドレスを持っています。

しかし、あなたWebサーバの間にはインターネットっていう空間がある・・・
ここをどうやってくっつけているのか、かなりざっくりと見てみます。

 

では、わかりやすくRPGにたとえてみましょう。
http://www.setjapan.co.jp」のWebサイトを見るというのは・・・
「setjapan.co.jp城にいるwww王http語を使って話したい」
という感じのクエストになります。

とりあえず、あなたは一番手近にいるDNSサーバってローカルな賢者に聞きます。
パソコンやらスマホやらに設定されているけど、大体は管理者が入れてるから、ほぼユーザは知らなくてよい話。

 

 あなたsetjapan.co.jp城www王話がしたいんすけど?
ローカル賢者.jpか。それなら賢者JPRSに聞くのじゃ。」

さすがはローカル賢者、なんも知りませんが、親切な彼は次の賢者を教えてくれます。
ちなみに”.jp”は、japanの意味で、JPRSが管理しているドメイン(TLD)です。

 

 あなたsetjapan.co.jp城ってどこすか?www王っています?
賢者JPRSsetjapan.co.jp城はこの場所にある。そこのNSというものに聞け」
どうやら、たらいまわしは賢者の得意技のようです。

場所は(なんとなく)わかったので、そこいってNSって人に聞きましょう。
このNSがsetjapan.co.jp内のIPアドレス(とか、諸々)の管理してます。

 

あなた「ここsetjapan.co.jp城っすか?www王っています?」
従者NSwww王はこの場所にいる。」と、王のIPアドレスを教えてくれます

やっと、王様に会えたので、http語で話しかけてみます。
あなた「王様、あのニュースどうなってんすか?」
www王「ほれ。こんな感じじゃ。うひゃひゃひゃw」
さすがwww王、名前通り草不可避です。

とまぁ、皆さんがWebを楽しんでる裏では
毎度こんな冒険が繰り広げられてるわけです。

 

でも、そうそううまくいかないこともあり
途中でどの賢者に聞いたらいいかわからなくなったり(ドメインサーバ不明)
王の場所分かったけどいなかったり(サーバダウン)
そもそも最初の賢者がいない(DNSサーバ未設定)
などをひっくるめて、「名前解決ができない」などと言ったりします。

なお。
説明の都合上、かなり端折ったり、デフォルメしていますので
もっとDNSサーバのことを知りたい人はSetJapanの門をたたいてみましょう。

 

【C#】デバッグ時に実行されるメソッドのトレースを出力する

 今回はC#デバッグ時に実行のトレースを行う方法を紹介します。用途としては非同期の場合にどこから呼出しされているか調査したいときなどに利用できるかと思います。
 方法としては2通りでCallerMemberNameAttributeクラスを利用する方法と、StackFrameクラスを利用する方法があります。

 以下はフォームにボタンのみを配置し、ボタンを押下すると出力ウィンドウへトレースの結果が出力されるサンプルとなっています。

デザイナー側実装

namespace DebugSample
{
  partial class Form1
  {
    /// <summary>
    /// 必要なデザイナー変数です。
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// 使用中のリソースをすべてクリーンアップします。
    /// </summary>
    /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param>
    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
      }
      base.Dispose(disposing);
    }

    #region Windows フォーム デザイナーで生成されたコード

    /// <summary>
    /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
    /// コード エディターで変更しないでください。
    /// </summary>
    private void InitializeComponent()
    {
      this.button1 = new System.Windows.Forms.Button();
      this.SuspendLayout();
      // 
      // button1
      // 
      this.button1.Location = new System.Drawing.Point(84, 64);
      this.button1.Name = "button1";
      this.button1.Size = new System.Drawing.Size(75, 23);
      this.button1.TabIndex = 0;
      this.button1.Text = "出力";
      this.button1.UseVisualStyleBackColor = true;
      this.button1.Click += new System.EventHandler(this.button1_Click);
      // 
      // Form1
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
      this.ClientSize = new System.Drawing.Size(255, 146);
      this.Controls.Add(this.button1);
      this.Name = "Form1";
      this.Text = "Form1";
      this.ResumeLayout(false);

    }

    #endregion

    private System.Windows.Forms.Button button1;
  }
}


 実行サンプル用にボタンが配置してあるだけのウィンドウズフォームです。

コードビハインド側実装

using System;
using System.Windows.Forms;

namespace DebugSample
{
  /// <summary>
  /// サンプル用フォーム
  /// </summary>
  public partial class Form1 : Form
  {
    /// <summary>
    /// クラスの新しいインスタンスを生成します。
    /// </summary>
    public Form1()
    {
      InitializeComponent();
    }

    /// <summary>
    /// button1がクリックされたときに発生します。
    /// </summary>
    /// <param name="sender">呼び出し元オブジェクト</param>
    /// <param name="e">イベント引数</param>
    private void button1_Click(object sender, EventArgs e)
    {
      DebugUtil.DebugTrace("出力テスト");

      Console.WriteLine("");

      DebugUtil.DebugTrace(5);
    }
  }
}


 実行のトレース出力を行うためのユーティリティクラスです。

デバッグ用のユーティリティクラス実装

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;

namespace DebugSample
{
  /// <summary>
  /// デバッグ用のユーティリティクラス
  /// </summary>
  public static class DebugUtil
  {
    /// <summary>
    /// 呼び出し元メンバーを出力します。
    /// </summary>
    /// <param name="message">デバッグ出力するメッセージ</param>
    /// <param name="member">呼び出し元のメンバー</param>
    /// <param name="filePath">呼び出し元のファイルパス</param>
    /// <param name="line">呼び出し元の行番号</param>
    public static void DebugTrace(string message = "", [CallerFilePath] string sourceFile = "", [CallerLineNumber] int line = 0, [CallerMemberName] string member = "")
    {
      if (!String.IsNullOrEmpty(message)) { Console.WriteLine(String.Format("Message => {0} ", message)); }
      Console.WriteLine(String.Format("Source File Name => {0}", Path.GetFileName(sourceFile)));
      Console.WriteLine(String.Format("Source Directory Path => {0}", Path.GetDirectoryName(sourceFile)));
      Console.WriteLine(String.Format("Method Name => {0}", member));
      Console.WriteLine(String.Format("Line Number => {0}", line));
    }

    /// <summary>
    /// 指定したフレーム数の呼び出し元メンバーを出力します。
    /// </summary>
    /// <param name="outputLevel">スキップするスタック上のフレーム数</param>
    public static void DebugTrace(int skipFrames)
    {
      // フレーム数が0より小さい場合、処理を行わない
      if (skipFrames < 0) return;

      // フレームが1つ前になるまで出力する
      for (int i = skipFrames; 1 <= i; i--) { FrameTrace(i); }
    }

    /// <summary>
    /// 指定したフレーム数の呼び出し元メンバーを出力します。
    /// </summary>
    /// <param name="outputLevel">スキップするスタック上のフレーム数</param>
    private static void FrameTrace(int skipFrames)
    {
      var frame = new StackFrame(skipFrames);
      var method = frame.GetMethod();
      Console.WriteLine(String.Format("Method Name => {0}", method.ReflectedType.FullName + "." + method.Name));
    }
  }
}


 以下は出力結果です。

Message => 出力テスト 
Source File Name => Form1.cs
Source Directory Path => c:\Users\xxxxxx\Documents\Projects\DebugSample\DebugSample
Method Name => button1_Click
Line Number => 26

Method Name => System.Windows.Forms.Button.OnMouseUp
Method Name => System.Windows.Forms.Button.OnClick
Method Name => System.Windows.Forms.Control.OnClick
Method Name => DebugSample.Form1.button1_Click
Method Name => DebugSample.DebugUtil.DebugTrace

 ユーティリティクラスのDebugTraceメソッドでメッセージ引数を持つメソッドの場合、行番号までが出力されます。
 DebugTraceメソッドでフレーム数引数を持つメソッドの場合、名前空間.クラス.メソッド名で出力されます。

ポートフォリオの表紙の作り方!(テンション高め)

ハローこんにちは!初めまして!


突然ですが!今就活をしているデザイナーさんやイラストレーターさん向けに、ポートフォリオについてのお話をしようかと思います。
ポートフォリオ片手に?いやいや、お菓子やコーヒー片手に!
まったーりしながらお聞きくださいね。

あなたはポートフォリオをどのように作っていますか?
真っ白な背景に頑張って作った作品を並べて印刷!ハイ完成!
というのはやめましょう。
分かります、まる分かりです、時間なかったとかバイト忙しいとか言い訳です、世界は残酷です……。
でも、あなたの夢を目指す魂はそんなもので尽きませんよね!
「作品に心をこめて、全ての思いを相手に伝える」ポートフォリオを作りましょう!


……いろいろ言いたいことはありますが、まずは一個だけ。


表紙には命をかける!


これです。ハイ。

……正直、文字って読むのが面倒なんですよねー。
文字の集合体を見ると、拒絶反応が起きますね!
もっとわかりやすくしてほしいなー……。
って思った私が、表紙を作っちゃいました。

 

ポイントとしては……

表紙は見られるか見られないかということも関わる顔の役目なので、いい作品を持ってくること。

ただし、全力を出すのはだめですよ?
全力を出せば、それ以上見る意味が無くなりますから。
そこで「チラ見(試し読み)」のような手段を使います。
「続きを見なきゃ!気になる!」って思わせる方法です。
ここでレイアウトが役に立ちます。
いい作品をチラ見させ、あえて全体が見えないようにする。
パッと見てまとまりがあるうえ、綺麗に整頓されていることで上級感を出します。
項目ごとのピックアップをひとつづつ……だとさらにいいと思いますよ!

 

f:id:atamo_dev:20170602181514p:plain


そんな感じで実際に創った表紙がこれです。

何が出来るの?っていうのが一発で分かるけど、細かいところは中じゃないと分からないっていうのがいいですよっ!


どうですか?

めくってみたくなるでしょう?

【RxSwift】RxSwiftを触ってみる

RxSwiftとは

ReactiveX(Reactive Extensions)のSwift実装で非同期のイベントベースのプログラムを実装するためのライブラリです。

導入

CocoaPodsやCarthageで導入可能です。

今回はCocoaPodsを使います。

target 'RxSwiftTest' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!
  pod 'RxSwift',    '~> 3.0'
  pod 'RxCocoa',    '~> 3.0'
  # Pods for RxSwiftTest

  target 'RxSwiftTestTests' do
    inherit! :search_paths
    # Pods for testing
    pod 'RxBlocking', '~> 3.0'
    pod 'RxTest',     '~> 3.0'
  end

  target 'RxSwiftTestUITests' do
    inherit! :search_paths
    # Pods for testing
    pod 'RxBlocking', '~> 3.0'
    pod 'RxTest',     '~> 3.0'
  end

end

使ってみる

テキストフィールドの入力をラベルへリアルタイムに反映してみます。

RxSwiftを使わないで実装する場合はUITextFieldのDelegateを実装したりNotificationを使う必要があります。

f:id:atamo_dev:20170515200329g:plain:w300

Delegateでの実装

class ViewController: UIViewController, UITextFieldDelegate {
    
    var label: UILabel = UILabel()
    var field: UITextField = UITextField()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // ラベルをViewへ追加
        label.frame.size = CGSize(width: UIScreen.main.bounds.size.width, height: 60)
        label.center = CGPoint(x: view.center.x, y: view.center.y - 100)
        view.addSubview(label)
        
        // テキストフィールドをViewへ追加
        field.frame.size = CGSize(width: UIScreen.main.bounds.size.width, height: 60)
        field.center = view.center
        field.borderStyle = .roundedRect
        field.delegate = self
        view.addSubview(field)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        
    }
    
    // MARK: - UITextFieldDelegate
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        guard let text = textField.text as NSString? else {
            return false
        }
        label.text = text.replacingCharacters(in: range, with: string)
        return true
    }
}

RxSwiftでの実装

これをRxSwiftで実装するとこうなります。

import UIKit
import RxSwift      
import RxCocoa      

let disposeBag = DisposeBag()   

class ViewController: UIViewController {
    
    var label: UILabel = UILabel()
    var field: UITextField = UITextField()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // ラベルをViewへ追加
        label.frame.size = CGSize(width: UIScreen.main.bounds.size.width, height: 60)
        label.center = CGPoint(x: view.center.x, y: view.center.y - 100)
        view.addSubview(label)
        
        // テキストフィールドをViewへ追加
        field.frame.size = CGSize(width: UIScreen.main.bounds.size.width, height: 60)
        field.center = view.center
        field.borderStyle = .roundedRect
        view.addSubview(field)
        
        // テキストフィールドのテキストをラベルへバインド
        field.rx.text.map {$0}.bindTo(label.rx.text).addDisposableTo(disposeBag)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        
    }
    
}

DelegateやNotificationを使用した場合は処理がいろいろな場所へ散乱してしまい非常に読みづらいですが、RxSwiftを使うとスッキリと書くことができます。

参考

http:// http://qiita.com/jollyjoester/items/c4013c60acd453ea7248

CG 背景イラスト 夏の海

f:id:atamo_dev:20170521155933p:plain

これからの季節、イラストに欠かせない夏の海を描いてみます。

 

使用ソフト:PhotoShop,SAI

ペンタブ:INTUOS PTH-851

 

今回作成したpsdファイルは下記URLに配置してあります。

https://drive.google.com/drive/folders/0B9dZ314mf8WoTGpYZVBqZmtzVUk?usp=sharing

再配布以外でしたら個人用途に限りご自由にお使いください。

報告も、配布元の表示も不要です。

 

1.PhotoShopで新規ファイルを作成

今回は横2000×縦1200でファイルを作成しました。

 

 

2.海と空のベースを作成

「グラデーションツール」を使い空と海の下地を描画します。

 f:id:atamo_dev:20170521164910p:plain

 

 

今回グラデーションに設定する色の値は、それぞれ下記の画像の通りです。

f:id:atamo_dev:20170518193623p:plain

 

1.新規レイヤーを作成 → 海面レイヤーと命名します

2.海面レイヤーに長方形選択ツールとグラデーションツールを使って海面を描く

3.続いて背景レイヤーを選択 → グラデーションツールを使い空を描く

f:id:atamo_dev:20170518194134p:plain

 

 

 3.砂浜のベースを作成

ボケ足の強いブラシツールを使って手前側に砂浜を描きます。

 f:id:atamo_dev:20170521164909p:plain

 

 

1.最上面に新規レイヤーを作成 → 砂浜レイヤーと命名

2.手前側に大ざっぱに砂浜の下地を描いていきます

f:id:atamo_dev:20170518194405p:plain 

ここまで描いたら一旦ファイルを保存し、PhotoShopを終了します。(保存形式はpsdを選択してください)

 

 

4.海面に明暗を描画

保存したファイルをSAIで開き、「水彩筆」を使って海面に明暗をつけます。

 f:id:atamo_dev:20170516202931p:plain

 

 

「水彩筆」の設定は下記の通りです。(今回使う水彩ブラシはこれのみ)

f:id:atamo_dev:20170515191956p:plain 

 

1.海面レイヤーを選択し、「水彩筆」を使って海面に明暗を描き込んでいきます。奥にいくほど暗く細かく、手前ほど明るく大きくなるように、ホライズンラインに沿って筆を動かします。飽くまで遠景なので細かく描く必要はありません。大雑把に描きます。

f:id:atamo_dev:20170518194625p:plain

 

 

5.波打ち際の作成

波打ち際に泡を描きます。この工程で一気に海っぽくなります。

 f:id:atamo_dev:20170521164911p:plain

 

 

1.砂浜レイヤーを選択 → 不当明度保護にチェックをいれる

2.「水彩筆」を使い海面との境界付近を暗く塗ります

f:id:atamo_dev:20170518194622p:plain

3.砂浜レイヤーの上に新規レイヤーを作成 → 泡レイヤーと命名

4.泡レイヤーに水彩ブラシを使い白色(R255 G255 B255)で泡を描きこみます。波打ち際にいくほど泡の密度を高くします。

f:id:atamo_dev:20170521141711p:plain

5.泡レイヤーの下に新規レイヤーを作成 → 泡影レイヤーと命名

6.泡影レイヤーにうっすらと泡の陰を落とします。

f:id:atamo_dev:20170521142121p:plain

 

 

6.砂浜の描き込み

砂浜に陰影をつけます。非常に地味な工程ですが、これをやっておくと完成度があがります。

 f:id:atamo_dev:20170521164912p:plain

 

 

1.砂浜レイヤーを選択 → 砂浜に濃い部分と淡い部分を描きこみます。細かく描く必要はまったく無く、表面をなでる程度でかまいません。

f:id:atamo_dev:20170521142851p:plain

ここで一旦ファイルを保存し、SAIを終了します。(保存形式は先ほどと同じpsd形式を選択してください)

 

 

7.砂テクスチャの作成

PhotoShopの「フィルター」を使って砂のテクスチャを作成します。

 f:id:atamo_dev:20170521164913p:plain

 

 

PhotoShopを立ち上げ、横2000pixel × 縦2000pixelで新規ファイルを作成します。

[フィルター] → [ノイズを加える] → [グレースケールノイズ]でざらついたテクスチャを作成します。 

f:id:atamo_dev:20170521144116p:plain

これを[選択範囲] → [全てを選択]し、[編集] → [コピー]でコピーしておきます。 

f:id:atamo_dev:20170521144117p:plain

 

 

8.砂テクスチャの貼り付けと合成

先ほど作成したテクスチャを砂浜に貼り付けます。

 f:id:atamo_dev:20170521164914p:plain

 

 

1.PhotoShopで先ほどまで描いていた海のファイルを展開。

2.砂浜レイヤーの上に砂テクスチャを貼り付けます。

3.[変形] → [遠近法]を使いテクスチャを変形。

f:id:atamo_dev:20170521144118p:plain

4.砂浜レイヤーと「クリッピングパス」を作成します。続いてレイヤーの合成モードを「焼き込みカラー」にし、透明度を調整(ここでは20%に設定)したうえで下の砂浜レイヤーと結合します。

f:id:atamo_dev:20170521144119p:plain

ここで再びファイルを保存し、PhotoShopを終了します。(保存形式はpsdを選択してください)

 

 

9.雲の描画

空に雲を描きます。今回は夏の海という設定なので夏らしく積乱雲を描いてみました。今回は海がメインなので簡単に。雲の描き方はまた別記事で紹介させてください。

 f:id:atamo_dev:20170521164915p:plain

 

 

1.SAIを開いて、背景レイヤーの上に新規レイヤーを作成 → 雲レイヤーと命名

f:id:atamo_dev:20170521144120p:plain

2.「筆」と「水彩筆」を使って雲のベースとなる形を描きます。

雲というと、ついついボケ足の強いブラシを使ってしまいがちですが、積乱雲の場合、ボカさずに輪郭を取っておいて、一部分のみをボカすことでメリハリがでます。

3.明るい部分と暗い部分を描き足し、それぞれ境界の一部分を周囲の色となじませていきます。

f:id:atamo_dev:20170521144121p:plain

 

 

10.仕上げ

海と空に諧調変化に差をつけて、遠近感を強調します。下記の手順で三つのレイヤーを作成し、それぞれに「エアブラシ」を使って色をおいていきます。

 f:id:atamo_dev:20170521164916p:plain

 

 

1.背景レイヤーの上に新規レイヤーの作成 → 諧調変化と命名

空の手前側を濃く鮮やかにします。

2.雲レイヤーの下に新規レイヤーの作成 → 雲なじませと命名

空と雲の間を明るくして、両者をなじませます。

3.海面レイヤーの上にに新規レイヤーの作成 → 手前光レイヤーと命名

レイヤー合成モードを「発光」にし、海面の手前に光を入れて明るくします。

f:id:atamo_dev:20170521193846p:plain

 

 

何となくさみしかったので近景に石垣と緑を描きました。近景を描くと奥行き感が出る気がします。

f:id:atamo_dev:20170521164917p:plain

 

完成。

 最後まで読んでいただきありがとうございました。

 

By SetJapanCorporation,Inc. Designer : すんすん。

【C#】Windowsフォーム アプリケーションでDispatcherTimerを利用する

 今回はWindowsフォーム アプリケーションでThreading.DispatcherTimerを使用してみます。
 Windows.Forms.Timerはスレッドセーフではありますが、WindowメッセージのWM_TIMERで処理されるため遅いという欠点があります。
 その点、DispatcherTimerはスレッドセーフかつ、UIスレッド内での動作が基本となっており、Forms.Timerを使うくらいならThreading.DispatcherTimerの使用を推奨します。
 WPFへ移行する際もそのまま利用できますし、Timers.TimerはWPFではサポートされていないため非常にお勧めです。

 フォームにラベルを配置し、ボタンを押すとテロップのように移動するサンプルとなっています。

デザイナー側実装

namespace DispatcherTimerSample
{
  partial class Form1
  {
    /// <summary>
    /// 必要なデザイナー変数です。
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// 使用中のリソースをすべてクリーンアップします。
    /// </summary>
    /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param>
    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
      }
      base.Dispose(disposing);
    }

    #region Windows フォーム デザイナーで生成されたコード

    /// <summary>
    /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
    /// コード エディターで変更しないでください。
    /// </summary>
    private void InitializeComponent()
    {
      this.button1 = new System.Windows.Forms.Button();
      this.label1 = new System.Windows.Forms.Label();
      this.SuspendLayout();
      // 
      // button1
      // 
      this.button1.Location = new System.Drawing.Point(186, 12);
      this.button1.Name = "button1";
      this.button1.Size = new System.Drawing.Size(86, 42);
      this.button1.TabIndex = 0;
      this.button1.Text = "移動開始";
      this.button1.UseVisualStyleBackColor = true;
      this.button1.Click += new System.EventHandler(this.button1_Click);
      // 
      // label1
      // 
      this.label1.Font = new System.Drawing.Font("メイリオ", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
      this.label1.Location = new System.Drawing.Point(169, 97);
      this.label1.Name = "label1";
      this.label1.Size = new System.Drawing.Size(116, 30);
      this.label1.TabIndex = 1;
      this.label1.Text = "移動する";
      // 
      // Form1
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
      this.ClientSize = new System.Drawing.Size(284, 262);
      this.Controls.Add(this.label1);
      this.Controls.Add(this.button1);
      this.Name = "Form1";
      this.Text = "Form1";
      this.Load += new System.EventHandler(this.Form1_Load);
      this.ResumeLayout(false);

    }

    #endregion

    private System.Windows.Forms.Button button1;
    private System.Windows.Forms.Label label1;
  }
}

 

 Visual Studioのプロジェクトの「参照の追加」→「アセンブリ」→「フレームワーク」と選択してWindowsBaseへの参照を追加してください。

コードビハインド側実装

using System;
using System.Windows.Forms;
using System.Windows.Threading;

namespace DispatcherTimerSample
{
  public partial class Form1 : Form
  {
    #region メンバ変数
    /// <summary>
    /// 画面更新制御タイマー
    /// </summary>
    DispatcherTimer _DispatcherTimer = new DispatcherTimer();
    #endregion

    #region コンストラクタ
    /// <summary>
    /// クラスの新しいインスタンスを初期化します。
    /// </summary>
    public Form1()
    {
      InitializeComponent();
    }
    #endregion

    #region イベント
    /// <summary>
    /// フォームが初めて表示される直前に発生します。
    /// </summary>
    /// <param name="sender">イベント発生オブジェクト</param>
    /// <param name="e">イベント引数</param>
    private void Form1_Load(object sender, EventArgs e)
    {
      this._DispatcherTimer.Tick += LabelMoveDispatcherTimer_Tick;
    }

    /// <summary>
    /// ボタンコントロールがクリックされたときに発生します。
    /// </summary>
    /// <param name="sender">イベント発生オブジェクト</param>
    /// <param name="e">イベント引数</param>
    private void button1_Click(object sender, EventArgs e)
    {
      this._DispatcherTimer.Interval = TimeSpan.FromMilliseconds(100);
      this._DispatcherTimer.Start();
    }

    /// <summary>
    /// タイマーの間隔が経過したときに発生します。
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void LabelMoveDispatcherTimer_Tick(object sender, EventArgs e)
    {
      if (this.label1.Left - 1  < -this.Left)
      {
        this.label1.Left = this.Width;
      }
      else
      {
        this.label1.Left -= 1;
      }
    }
    #endregion
  }
}

 わたしの担当時、今期はWindowsフォーム アプリケーションで色々とサンプルをご紹介してきましたが、まだまだ業務では使えるかな?という印象でした。
 来期もまた別のテーマで色々とナレッジを残せたらと思います。

【Android】よく使う共通処理【Util】

個人的によく使う処理です。
Utilにまとめておくと意外と便利!

/**
 * クリップボードにコピー
 */
public static void copy(Context c, String label, String text) {
  android.content.ClipboardManager cm = (android.content.ClipboardManager)c.getSystemService(Context.CLIPBOARD_SERVICE);
  cm.setPrimaryClip(ClipData.newPlainText(label, text));
}

/**
 * 画面横サイズ取得
 */
public static int getDisplayWidth(Context context) {
  try {
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    return metrics.widthPixels;
  } catch (Exception e) {
    return 0;
  }
}

/**
 * 画面縦サイズ取得
 */
public static int getDisplayHeight(Context context) {
  try {
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    return metrics.heightPixels;
  } catch (Exception e) {
    return 0;
  }
}

/**
 * dip → px 変換
 */
public static int dipToPixel(Context context, int dp) {
  return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}

/**
 * 色を少し明るくする
 */
public static int lighter(int color, float factor) {
  int red = (int) ((Color.red(color) * (1 - factor) / 255 + factor) * 255);
  int green = (int) ((Color.green(color) * (1 - factor) / 255 + factor) * 255);
  int blue = (int) ((Color.blue(color) * (1 - factor) / 255 + factor) * 255);
  return Color.argb(Color.alpha(color), red, green, blue);
}

/**
 * 色を少し暗くする
 */
public static int darker (int color, float factor) {
  if (factor < 0 || factor > 1) return color;
  int r = Color.red(color);
  int g = Color.green( color );
  int b = Color.blue( color );
  return Color.argb(Color.alpha(color), Math.max((int)(r * factor), 0), Math.max((int)(g * factor), 0), Math.max((int)(b * factor), 0));
}

/**
 * 現在時刻を取得
 */
public static String now() {
  return now("yyyy-MM-dd HH:mm:ss", TimeZone.getDefault().toString());
}
public static String now(String format) {
  return now(format, TimeZone.getDefault().toString());
}
public static String now(String format, String timeZone) {
  Date date = new Date();
  return FastDateFormat.getInstance(format, TimeZone.getTimeZone(timeZone)).format(date);
}

/**
 * data/data/パッケージ名/filesの下にフォルダを作成し、作成したフォルダのパスを返却
 */
public static String makePkgFilesDir(Context context, String folderPath) {
  String path = context.getFilesDir().getAbsolutePath() + "/" + folderPath;
  // ディレクトリがない場合は作成
  File makeDir = new File(path);
  if (makeDir.exists() == false) makeDir.mkdirs();
  return path;
}

/**
 * ディレクトリ、ファイルの削除
 */
public static boolean delete(File f) {
  if (f.exists() == false) return false;
  
  if (f.isFile()) {
    f.delete();
  } else if (f.isDirectory()) {
    File[] files = f.listFiles();
    for (int i = 0; i < files.length; i++) {
      delete(files[i]);
    }
    f.delete();
  }
  return true;
}

/**
 * キーボード表示
 */
public static void show(Activity activity) {
  if(null == activity) return;
  
  InputMethodManager imm = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
  View v = activity.getCurrentFocus();
  if(null != v) {
    imm.showSoftInput(v.findFocus(), 0);
  }
}

/**
 * キーボード非表示
 */
public static void hide(Activity activity) {
  if(null == activity) return;
  
  InputMethodManager imm = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
  View v = activity.getCurrentFocus();
  if(null != v) {
    imm.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
  }
}

【Swift】xmlで管理している色情報を簡単に扱う

はじめに

今回は、xmlで色を管理した場合に、簡単に扱えるようにしたいと思います。

xmlについて

以下のフォーマットでxmlを用意します。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="buttonBackGround">#285176</color>
    <color name="buttonText">#305c83</color>
    .
    .
    .
</resources>

コード

今回は、色に関してのみですが、xmlファイル1つで色々とまとめて管理することができるので、使い回しがしやすいように、クラスを分けています。

class XMLUtil: NSObject,  XMLParserDelegate {
    
    var parser: XMLParser!
    
    var compleationBlock: (([String : String]?)->Void) = {_ in}
    var element: String!
    var attribute: String!
    var tmpDic: [String : String]!
    var tmpKey: String!
    
    public func parse(fileName: String, element: String! = nil, attribute: String! = nil, compleation: @escaping (([String : String]?)->Void)) {
        self.element = element
        self.attribute = attribute
        compleationBlock = compleation
        
        guard let tmpData: Data = loadAssetFile(name: fileName) else {
            self.compleationBlock(nil)
            return
        }
        
        parser = XMLParser(data: tmpData)
        parser.delegate = self
        
        let _ = parser.parse()
        
    }
    
    private func loadAssetFile(name: String) -> Data! {
        var data: Data! = nil
        // Assetsから取得
        if #available(iOS 9.0, *) {
            if let tmpData = NSDataAsset(name: name) {
                data = tmpData.data
            }
        } 
        return data
    }
    
    // MARK: - NSXMLParserDelegate
    
   public func parserDidStartDocument(_ parser: XMLParser) {
        tmpDic = [ : ]
    }
    
    public func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
        
        guard let _ = element else {
            tmpKey = elementName
            return
        }
        guard let _ = attribute else {
            tmpKey = element
            return
        }
        if elementName == element {
            guard let key = attributeDict[attribute] else {
                return
            }
            tmpKey = key
        }
    }
    
    public func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        tmpKey = nil
    }
    
    public func parser(_ parser: XMLParser, foundCharacters string: String) {
        guard let _ = tmpKey else {
            return
        }
        tmpDic[tmpKey] = string
    }
    
    public func parserDidEndDocument(_ parser: XMLParser) {
        self.compleationBlock(tmpDic)
    }
}
class XMLColorUtil: NSObject {
    private var colors: [String : String]! = nil
    
    static var shared: XMLColorUtil = {
        let instance = XMLColorUtil()
        let res = instance.loadColors()

        return instance
    }()
    private override init() {
    }
   
    internal func loadColors() {
        var finish = false
        XMLUtil().parse(fileName: "colors", element: "color", attribute: "name") {
            dic in
            if dic != nil {
                self.colors = dic
            }
            finish = true
        }
        
    }
    
    public func getColor(key: String = #function) -> UIColor {
        guard let _ = colors else {
            return .white
        }
        guard let hexColor = colors[key] else {
            return .white
        }
        return UIColor(hex: hexColor)
    }
}
extension UIColor {
    convenience init(hex: String) {
        let range = NSMakeRange(0, rgbString.characters.count)
        let hexStr = (rgbString as NSString).replacingOccurrences(of: "[^0-9a-fA-F]", with: "", options: .regularExpression, range: range)
        
        var r: Float = 1
        var g: Float = 1
        var b: Float = 1
        let a: Float = 1
        if hexStr.characters.count == 6 {
            if let num = Int(hexStr, radix: 16) {
                r = Float((num >> 16) & 0xFF) / 255.0
                g = Float((num >> 8) & 0xFF) / 255.0
                b = Float((num) & 0xFF) / 255.0
            }
        }
        self.init(red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: CGFloat(a))
    }
}

色クラス

class AppColor: NSObject {
    private let util = XMLColorUtil.shared
    
    // xml上のnameと合わせる
    public var buttonBackGround: UIColor {
        return util.getColor()
    }
    public var buttonText: UIColor {
        return util.getColor()
    }
    .
    .
    .
}

このクラスに上にxmlでname属性に設定した値をプロパティとして定義し、XMLColorUtilクラスのgetColor()を呼びます

getColor()の引数の初期値は#functionなので、呼び出し元のメソッド名を取得するようになっています。

XMLColorUtil().getColor(key: "buttonBackGround")とすることもできます。

使い方

let appColor = AppColor()

let button = UIButton(frame: CGRect(origin: .zero, size: CGSize(width: 100, height: 60)))

button.backgroundColor = appColor.buttonBackGround
button.setTitleColor(appColor.buttonText, for: .normal)

使用する色が増えた際には、xml編集後、AppColorクラスにプロパティを追加するだけで使えるようになります。