ラベル UI部品 の投稿を表示しています。 すべての投稿を表示
ラベル UI部品 の投稿を表示しています。 すべての投稿を表示

2019年10月10日木曜日

ダークモードの回避

左が正常なのに、ダークモードだと右の表示になる
Labelの文字が白くなり、TextViewの背景が真っ黒に

iOS13とXcode11、macOS 10.15 Catalinaにした後にアプリを審査に出したら、表示が見づらいからってリジェクトされた。
なんじゃこりゃ、TextViewの背景色なんていじった覚えないぞ!? と思ったが、iOS13から付けられた(余計な)機能、ダークモードのせいだった。
どうやら新しく提出したアプリから影響するらしい。

UISegmentedControlの色もこのとおり

回避方法


Info.plistのUser Interface Style を Light にすればアプリ丸ごとこれまでのライトモードで動いてくれる。
親方様(アップル)としてはダークモードへの対応を推奨してるんだろうけど、また今度ね!
しかしどうしてこう、いちいちデベロッパーに無理な負担を強いるかなあ…。

2019年9月22日日曜日

Xcode11リリース

2019/9/20にiPhone用にiOS13が、1日遅れの顰蹙でXcode11がそれぞれリリースされた。
iPadの方は新しくiPadOSになるということで、リリースはもうちょっと後らしい。
iOS13はダークモードがある以外は見た目にはあまり変化がない。

以下、とりあえず気づいた点だけ。

デバイス欄にiPhone、iPadに加え、Macが!


iPadOSとmacOSで共通のアプリを作れるような話もあるが、まさかmacOS 10.15 Catalinaにしたら一本のコードでiPhone、iPad、Macで共通のアプリなんて作れたりする?
それとも表示されてるだけで、iPadOSかmacOS用のテンプレートじゃなきゃここがenableにならんか?

SwiftUI

これまでのAutoLayoutのStoryboardとプロジェクトを作る段階で選択になる。
作成時、User Interfaceのメニューで選択

ひな形からプロジェクトを作成するとこれまでのViewControllerの代わりにSceneDelegate.swift、ContentView.swiftというファイルが作られている。

SceneDelegateはUIWindowSceneの状態が変化した時のdelegateメソッドが並んでる。これがUIViewControllerのviewDidLoadとかの代わりになるのかはよくわからん。

ContentViewの方が実際に画面デザインのコードを記述するファイルとなるようだ。
中に書かれたContentView構造体はSwiftUI用のviewプロトコルを継承した構造体の定義になっている。まだよくわかんないけど、ここに書くってことさえ覚えときゃいいか。

SwiftUIを勉強しようとしたのだが、コードと1対1のプレビューが出てこない。これMacもCatalinaに上げないといけないんだって(今はβだけ)。リリースまでおあずけ。コードを試すだけしかない。

単にAutoLayoutのconstraints設定を新しくするようなものでなく、UI部品の配置までコードとともに見えるようになるわけだな? ActionやOutletの接続はどうなるのやら。プレビューが見られるようになった場合、segueで繋がれたViewController同士の関係性とか見られるのかね?
Storyboardと併用できないようなので、早めに覚えてしまいたい。
詳しいことがわかったら勉強がてら別にまとめる。

ボタンアイコンを大量に搭載


Storyboardで右上の「+」ボタン(UI部品を選ぶ所)を押すとボタンなどのアイコンデザインが大量に出てくる。今までほんの少ししか搭載されておらず、あとは自作するしかなかったシステムアイコンだが、ようやくこれで統一が図れる。
StoryboardにドラッグするとImageViewとして貼られる。名前を指定すればコード中からも使える。

Swift UIを選択した場合は「+」ボタンの中にこの一覧がないんだが、別に見られるのかしら? まあ、UIButtonとかのImage名を入れるとこのメニューに名前が出てくるけどね。
アイコン画像サイズは最小しかない?

RealityKit

ARのテンプレートにRealityKitというContent Technologyが選択できるようになった。
RealityComposerというXcode内のアプリを使ってARに表示する物を編集できるようなのだが、まだよくわからない。
テンプレートをそのままRunするとタッチした正面に3Dの立方体を1個表示するアプリができる。
Composerでその質感とかを変えられるようなのだが、変えるとエラーが出るのでよくわからん。

2019年1月2日水曜日

SKLabelNodeの文字を縁取りに

NSMutableAttributedStringクラスを使う。

以下のコードの内、strokeWidthが縁取りの太さになるのだが、正の数だと縁取りだけで中が塗られない袋文字になる。負の値だと縁取り+中の塗りつぶしになる。
strokeColorが縁取りの色、foregroundColorは中の塗りつぶし色。

let borderText = NSMutableAttributedString(string: "縁取る文字")
borderText.addAttributes([NSAttributedString.Key.strokeWidth : -2.0,
NSAttributedString.Key.strokeColor : UIColor.black,
NSAttributedString.Key.foregroundColor : fontColor,
NSAttributedString.Key.font : UIFont.systemFont(ofSize: 64.0)],
range: NSMakeRange(0, borderText.length))
labelNode.attributedText = borderText

注意点

同時にSKLabelNode.textに普通にcolorを設定すると、そちらが優先されたりされなかったり、挙動がおかしくなる場合がありよくわからない。
要するに両方同時に設定しないほうが無難。

また、SKLabelNodeの.textと、NSMutableAttributedStringのstringは別物になる。

SKLabelNodeの色を変える

UILabel同様にSKColor()のメソッドで色を指定する点は一緒。

その後、colorBlendFactor という色の濃さのプロパティを指定してやらないと思い通りの色で表示されない。(白で表示されてしまう)
alpha値同様、1.0が最も濃い。
labelNode.colorBlendFactor = 1.0

めんどくせえな。

2018年6月5日火曜日

WWDC2018

ゆんべ美國でおこなわれたWWDCの開発関係の自分用まとめ。


  • iOS 12発表
    • リリースは秋
    • インストール対象はiOS11が動くデバイス
    • パフォーマンスが向上
    • Pixarと共同でAR関係の新ファイルフォーマット USDZ(ユーエスディーズィー) を開発
    • Apple純正AR物差しアプリ 「Measure」発表
    • ARKit 2発表
      • 顔認識やレンダリングその他を改良、最大4人のマルチユーザをサポート
    • その他もろもろ
  • macOS Mojave(モハーベ)発表
    • リリースは秋
    • iOSのUIKitをmacOSに導入
      • Appleからニュース、株式、音声メモ、ホームの各iOSアプリをMac用にリリース
      • 2019年にデベロッパにも提供され、iOSアプリをmacOSに移植可能に
      • iOSとmacOSの統合は否定
OSの改良でパフォーマンス向上してくれるのは歓迎。
でもまたいろいろいじらなきゃいけない点が出てくるだろーなー。仮により簡単に作れるようになったとしても、概念や扱い方が大きく違ったりすると直すのがめんどい。こちとら新しいアプリ作りたいんじゃ。過去のアプリのサポートばっかりやってられるかい!

ARKit1もまだよく使ってない。こないだiPhone買ったばかりだし。
Measureって、日本のAppStoreに同名のアプリ(個人開発)があるんだけど、いいのか? まさかそのアプリを買収するわけじゃないよね?

UIKitがMacでも使えるようになるのはいいね。扱いが統一されるとやりやすい。移植可能になるというより、移植が楽になるってこっちゃな。今までのmacOSのUIを司ってたAPIを置き換えちゃうわけじゃないんでしょ?
iOSはUIKitだけにあらずなので、そのほかのAPIというかFrameworkの互換性ってのはどんなもんなのかね?

2018年5月28日月曜日

複数のジェスチャーでViewをアフィン変換

やりたいこと

ピンチやローテートのジェスチャーを複数組み合わせてView(ImageView)の形を変更したい。
ジェスチャーは複数を一度に使えるように。

やり方

UIGestureRecognizerのdelegateを設定し、delegateメソッドで複数のGestureRecognizerの同時使用を許可。
複数のアフィン変換を組み合わせる処理をしてからViewに反映させる。
ジェスチャー(例ではpinchとrotate)使用中のtransformの状態と、終了時のtransformの状態をそれぞれ保存し、ジェスチャー開始時(再開時)は前回の続きから始めるようにする。

つまづいたとこ

Swift3あたりから書き方が変わったせいで、前回のtransformの状態から再開する方法、複数のアフィン変換を組み合わせるコードに迷った。

コード(Swift4)

class ViewController: UIViewController,UIGestureRecognizerDelegate {
    
    var myView = UIImageView()
    
    //ジェスチャーで変化中のtransformを保存
    var prevRotate = CGAffineTransform()
    var prevScale = CGAffineTransform()
    //ジェスチャー終了時のtransformを保存
    var prevEndRotate = CGAffineTransform()
    var prevEndScale = CGAffineTransform()
    

    override func viewDidLoad() {
        super.viewDidLoad()
        
        myView = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
        myView.image = UIImage(named: "image")
        myView.transform = CGAffineTransform.identity //念のため変形を初期化
        myView.isUserInteractionEnabled = true //ユーザーインタラクションを許可
        myView.center = CGPoint(x: self.view.frame.midX, y: self.view.frame.midY)
        self.view.addSubview(myView)
        
        let rotate = UIRotationGestureRecognizer(target: self, action: #selector(ViewController.rotate))
        rotate.delegate = self
        myView.addGestureRecognizer(rotate)
        
        let pinch = UIPinchGestureRecognizer(target: self, action: #selector(ViewController.pinch))
        pinch.delegate = self
        myView.addGestureRecognizer(pinch)
        
        //アフィン変換の初期値設定しとかないとダメ
        prevRotate = myView.transform
        prevScale = myView.transform
        prevEndRotate = myView.transform
        prevEndScale = myView.transform
    }

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

    @objc func rotate(sender:UIRotationGestureRecognizer) {
        //前回のrotateの続きからrotateする
        let nowRotate = prevEndRotate.rotated(by: sender.rotation)
        //複数のアフィン変換を組み合わせる
        myView.transform = nowRotate.concatenating(prevScale)
        prevRotate = nowRotate

        //rotate終了時のtransform状態を保存
        if sender.state == .ended {
            prevEndRotate = nowRotate
        }
    }

    @objc func pinch(sender:UIPinchGestureRecognizer) {
        //前回のpinchの続きからscaleを変える
        let nowScale = prevEndScale.scaledBy(x: sender.scale, y: sender.scale)
        //複数のアフィン変換を組み合わせる
        myView.transform = nowScale.concatenating(prevRotate)
        prevScale = nowScale

        //pinch終了時のtransform状態を保存
        if sender.state == UIGestureRecognizerState.ended {
            prevEndScale = nowScale
        }
    }
    
    //複数のrecognizerの同時使用許可
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

参考サイト

2018年5月10日木曜日

MenuControllerを表示

この「複製/削除」ね
Text関係をタップした時なんかにコピー/カット/ペースト/ユーザ辞書…とか表示される横長のメニューあるでしょ? あれを使いたいの。

お約束としてやらなきゃならないことはあるけど、難しくないんでコードだけ書いとく。
UIViewのサブクラスとして作っておかないとcanPerformAction()とかが使えないので注意。
タップしてメニューを出したいUIをFirstResponderにするのがキモ。TextFieldとかなら、編集始めると自動でFirstResponderになってくれるからその辺の処理がいらないかも?


//Swift4
//メニュー表示
func makeMenu() -> Void {
    //先にFirstResponderにしとかないとメニューは表示されない
    becomeFirstResponder()
    //複製、削除メニュー
    let menu = UIMenuController.shared
    menu.isMenuVisible = true
    menu.arrowDirection = .up //メニューの矢印(ふきだしのしっぽみたいなの)の向き
    menu.setTargetRect(self.bounds, in: self)
    //メニューアイテム
    let menuItem1 = UIMenuItem(title: "複製", action: #selector(Fukidasi.onDuplicate(sender:)))
    let menuItem2 = UIMenuItem(title: "削除", action: #selector(Fukidasi.onDelete(sender:)))
    let menuItems = [menuItem1, menuItem2]
    menu.menuItems = menuItems
    menu.setMenuVisible(true, animated: true)

}


//ふきだしのUIViewがFirstResponderにならないとメニューは表示されない
//以前はfuncだったものが最近readOnlyでfalseを返すvarに変わったので、overrideしてtrueを返させる
override var canBecomeFirstResponder: Bool {
    return true
}

//これmenu表示に必要
override func canPerformAction(_ action: Selector, withSender sender: Any!) -> Bool {
    if action == #selector(Fukidasi.onDuplicate(sender:)) ||
        action == #selector(Fukidasi.onDelete(sender:)) {
        return true
    }
    return false
}

@objc func onDuplicate(sender: UIMenuItem) {
    print("複製された")
}

@objc func onDelete(sender: UIMenuItem) {
    print("削除された")
}

2017年2月28日火曜日

CALayer覚え書き

よくわかってないんだけど、UIViewとCALayerの違いなどについて。

CALayerはアニメーション実行のFrameworkであるCoreAnimationが提供する仕組みで、その名の通り画像をアニメーションやお絵かきをさせるのに使う。
データとしてはビットマップグラフィックとして持っている。
レイヤーっつーんだから、透明なお絵かき板みたいな概念のものだろう。
CALayerを直接操作するには、事前にQuartzCore/QuartzCoreのFrameworkのimportが必要。

UIViewはお絵かき、アニメーション以外の部分、たとえばタッチした時のイベント処理とかの機能を提供している。

UIViewのインスタンスを作るとCALayerが自動的に作られるため、通常はUIViewに向けたメソッドやプロパティをいじることで、内包しているCALayerを使ったアニメーションも実現できる。

UIViewに別なViewやButtonなどをaddSubviewするように、CALayerに別なCALayerをaddSublayerすることもできる。
透明なお絵かき板を何枚も重ねて、それぞれが直接干渉しない形で動かしたりするイメージだろうか。

間違ってるかもしれないけど、たぶんだいたいこんな感じじゃないかと思う。
もっと詳しくわかったら追記する。

2017年2月18日土曜日

UIBarButtonItemの画像をきれいに表示する

UIBarButtonItemに画像を使用した場合、実サイズで表示されてしまうため、よほど小さい画像にしてやらない限り大きくはみ出してしまう。
かといって小さい画像にしてやると、Retinaディスプレイでもジャギーが目立つ粗いものになり、見た目がよろしくない。

UIButtonやUIImageViewにはContentModeの設定(Scale To FillとかAspectFitとか)ができ、部品の大きさに合わせて画像を縮小表示してくれるのだが、UIBarbuttonItemにはそんなものはない。

一瞬悩んだが、XcodeのAssetsに2x、3xの画像を登録すればいいことがわかった。


画像の大きさは20*20ピクセルがいいらしく、2xでは40*40、3xでは60*60の画像を登録した。

なお、今更ではあるけど、iOS7から(だっけ?)のフラットデザインの方針により、カラー画像を登録してもモノクロになっちゃうので、白く抜きたいところをalpha値 = 0 で描いた画像を使わなきゃいけない。
やり方によっちゃカラーの画像も使えるんじゃないかと思うんだけど、それはまた必要になったら調べるなり。