Month: May 2018

Swift:modal delegate vs. storyboard ID

iOSの画面遷移の仕方がよくわかっていないという根本的な問題は一旦横に置いて、結局、storyboard IDで遷移した方が簡単です。

それに、独立性が高いので、書き方・考え方だけでなく、呼び出しも簡単です。結局、全部、storyboard IDで遷移する方法に書き換えました。もうひとついい点は、entry pointを設定しなくても遷移できるので、UIを一箇所にまとめて管理できます。

Screenshot 2018-05-30 21.27.23

Swift4:UITextView文字列へのリンク設定

UITextViewの文字列にリンク(URL)を設定する方法は、基本的には、色付の機能と同じ手順になります。

注意点は次の通りでした。

  • UITextViewの選択された文字列を覚えておく。
  • リンクを入力してもらう。
  • 選択された文字列にリンクを設定し、色付を行う。
    • ここでは、NSMutableAttributedStringでハンドリングする必要があり、UITextView⇆UILabel間で変換しないと、うまくいきません。
    • また、リンクを取得したあと、どこでその処理をキックするかにより色の制御ができません。

Screenshot 2018-05-29 07.10.38

Swift4:UIImageのリサイズ

リサイズするとボケる、あるいはリサイズの仕方はどうすればいいの?

スクリーンショットを撮ってリサイズする機能を実装してはじめて成程と納得しました。ボケることについては、画像が粗くなる(画像が劣化する)!?で言及されています。

実際のリサイズのコードについては、【Swift4】UIImageで画像のサイズ変更、指定した倍率で拡大/縮小に書いてある通りです。そのままで動きます。

注意:拡大・縮小比率を求めるとき、結果から-0.002すれば、該当図形枠からはみださずに収まりました。高さからマイナスして計算したのですが、それではうまく行きませんでした。参考まで。

Screenshot 2018-05-29 01.18.53

Swift4:サブスレッドで同期処理

iOSの同期処理の仕方をそもそもわかっていないこともあり、少し苦労しました。

訂正:サンプルプログラムへの影響はありませんが、画像で貼り付けたコードは正しく動作していないことが判明しました。呼び出されたB側でExecLink()を呼び出していたため、同期処理をしないものと同様の動作になってしまい、正しい結果が得られていました。

しかし@shtnkgmさんに助けて頂きました。感謝です。参照したページはSwiftで複数の非同期処理の完了時に処理を行うです。

そもそも根本的につまづいた点は、main threadでないと同期がうまくいかない(暴走してしまう)という点です。これは2行追加すればいいと教えてもらい、すぐにやってみたのですが、ロジックはうまく通っているのですが、UIに結果が反映されません。バグだとわかっていても、すぐに検出できず、一晩寝て、今朝、1行削除し過ぎたことに気づきました。

やりたかったこと:

  • 「UITextViewの選択された文字列にリンクを入れる」とき、リンクを予め用意したUITextFieldに入れるのでなく、ポップアップ画面を出して入れるようにしたい。
  • そうすれば、UITextFieldを画面に用意しなくてすみます。

Screenshot 2018-05-24 19.38.46

Xcode9.3.1サンプルコードはここにあります。コードは基本的に@shtnkgmさんがアップされているものと同じです。

 

 

 

Swift4:UITextViewにリンクを設定

UITextViewの選択されたテキストにURLリンクを設定できるようにしました。

この実装でひとつだけ注意するべきことがありました。次のエラーが出てしまうのです。

@IBOutlet weak var yUserNote:UITextView!
@IBOutlet weak var yLink:UITextField!

yUserNote.linkTextAttributes    = [NSAttributedStringKey.foregroundColor.rawValue:  colorLiteral(red: 1, green: 0.2527923882, blue: 1, alpha: 1)]

Cannot assign value of type ‘[NSAttributedStringKey : UIColor]’ to type ‘[String : Any]!’

これはSwift4.0からのようです。
参考:Swift 4.0でNSAttributedStringの装飾属性Dictionaryがエラーになる件

結局、次のようにしたらこの文法エラーは消えました。

yUserNote.linkTextAttributes    = [NSAttributedStringKey.foregroundColor.rawValue:  colorLiteral(red: 1, green: 0.2527923882, blue: 1, alpha: 1)] as [String:Any]

Screenshot 2018-05-18 11.20.48

 

 

Swift4:文字列に色付(ソースコード)

UITextViewの任意の文字列をユーザーが選択し、色をつけることができる機能を実装しました。ソースコードはここ

文字数の問題:

最初、UITextViewの.textを選択された文字列、その前の文字列、その後の文字列に分けて抽出し、NSMutableAttributedStringで色付けしたものと合成する方法で実装を進めました。しかし、この方法だと、yUserNote.selectedRangeで入ってくる選択範囲に絵文字が含まれると、文字数ではなく、バイト数で入ってくることがわかりました(参考:文字列の長さを取得)。ソースコードの最後にあるCallGetStringByNSRangeを参考にしてください。

  • 重要:文字列に2バイトコードが含まれる場合、pString.utf16.count のような表現にしないと、yUserNote.attributedTextと生合成が保てない。

文字属性の設定の仕方:

そこで、抽出合成方法を放棄し、次の通り、UITextViewをNSMutableAttributedStringでUILabelに取り出し、選択文字列だけを色付けし、UILabelからUITextViewに戻す実装にしました。wAtt = yUserNote.attributedText as! NSMutableAttributedStringとすると、Xcodeのバグと思われるのですが、この命令で以上してしまうため、その迂回作としてUILabel➡︎UITextViewとしました。

  • 重要:UITextViewは直接NSMutableAttributedStringをハンドリングできないが、UILabelを仲介すれば、うまくいく。

import UIKit                                                        //
import WebKit                                                       //
class MesaNote: UIViewController, WKNavigationDelegate, WKUIDelegate {//
    @IBOutlet weak var  yUserNote:UITextView!                       //Note area
    var wRangeOrg:NSRange               = NSRange()                 //
    var wAtt:NSMutableAttributedString  = NSMutableAttributedString()//
    var wLabel:UILabel                  = UILabel()                 //
    override func viewDidLoad() {                                   //
        super.viewDidLoad()                                         //
        let wkString2:String        = “012345678900️⃣1️⃣abcde”        //
        yUserNote.attributedText    = NSAttributedString(string: wkString2,//
          attributes:[.foregroundColor :UIColor.blue, .font :UIFont(name: “Arial-BoldMT”, size:15)!])//
    }//============================================================//

    @IBAction func ExecIBAColor(){                                  //<*Add color to the selected text*>
        wRangeOrg                   = yUserNote.selectedRange       //
        wLabel.attributedText       = yUserNote.attributedText      //
        wAtt                        = wLabel.attributedText as! NSMutableAttributedString//
        wAtt.addAttributes([.foregroundColor : UIColor.red], range: wRangeOrg)//
        yUserNote.attributedText    = wAtt
    }//============================================================//

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

 func CallGetStringByNSRange(_ pString:String, pRange:NSRange) -> String {//<*NSRange指定範囲の文字列を抽出する*>
        if pRange.location >= pString.utf16.count || pRange.location < 0
           || pRange.length <= 0 || pRange.location+pRange.length > pString.utf16.count { return “” }
        return String(pString[Range(pRange, in: pString)!])         //
    }//=============================================================//
}

Screenshot 2018-05-16 23.59.29

Swift4:UITableViewの高さ

UITableViewの高さ、行数、行の高さ・ヘッダーの高さ、先頭行位置、最終行位置などの操作についてのメモです。

この作表においては、.reloaData()を適当に入れたためこれが悪さし、各行の更新が終わらないようになり(ループしてしまい)、とても苦労しました。Z.bookArrayは[String]でbookmarkの配列になります。wkGyosuPerPageはInt、wkRowsizeとwkHeadersizeは常数(Int)です。

🔴 先頭行へのスクロールは単純です(Scroll to the top)。

    @IBAction func IBAExecGo2Top() {                                //スクロール先頭
        self.vTableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)//
        wkIndexPath                 = IndexPath(row: 0, section: 0) //
    }//=============================================================//

🔴 最終行へのスクロールは1ページの行数と最終行位置で計算をする必要があります。
(Scroll to the bottom. Calculate the rows in the last page.)

wkGyosuPerPage = Int((vTableView.frame.height – wkHeadersize) / wkRowsize)

    @IBAction func IBAExecGo2Bottom() {                             //スクロール最後
        var wRow:Int                = Z.bookArray.count – 1         //最後の行位置
        if wRow < wkGyosuPerPage    { wRow   = 0 }                  //1ページ内に収まるとき、先頭行から表示。
        else                        { wRow   = wRow – (wkGyosuPerPage – 1) }//最終行ー(1ページ行数1)から表示。
        self.vTableView.scrollToRow(at: IndexPath(row: wRow, section: 0), at: .top, animated: false)//
        wkIndexPath                 = IndexPath(row:wRow, section:0)//
    }//=============================================================//

🔴 表全体の行数(The number of rows in all.)

    func tableView(_ tableView:UITableView, numberOfRowsInSection section:Int) -> Int {//表の行数を返す
        return Z.bookArray.count                                    //☎️♻️return♻️ bookmarkの行数
    }//=============================================================//☎️

🔴 表示(Edit the row.)

    func tableView(_ tableView:UITableView, cellForRowAt indexPath:IndexPath) -> UITableViewCell {//表示
        var wCell:UITableViewCell                                   //☎️
        wCell = ExecSetValue(tableView, pIndex:indexPath)           //☎️表に値をsetする。wCellは編集結果。
        return wCell                                                //☎️♻️return♻️ infoArray cellを返す。
    }//=============================================================//☎️

🔴 クリック時の処理(The process for the selected row.)

    func tableView(_ tableView:UITableView, didSelectRowAt indexPath:IndexPath) {//クリックした行位置
        ExecClickedRow(indexPath.row, pCount:indexPath.count)       //☎️
        vTableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
    }//=============================================================//☎️

🔴 行の高さ(The height definition execpt the header.)

    func tableView(_ tableView:UITableView, heightForRowAt indexPath:IndexPath) -> CGFloat {//行の高さ
        return wkRowsize                                            //☎️
    }//=============================================================//☎️

🔴 ヘッダーの高さ(The height definition for the header.)

   func tableView(_ tableView:UITableView, heightForHeaderInSection section:Int) -> CGFloat {//ヘッダ高さ
       return wkHeadersize                                         //☎️
   }//=============================================================//☎️

🔴 ヘッダーの表示(Edit the header.)

    func tableView(_ tableView:UITableView, viewForHeaderInSection section:Int) -> UIView? {//ヘッダー設定
        let wHeader = ExecSetHeader(tableView, pSection:section)    //☎️ヘッダーを設定する。
        return wHeader                                              //☎️
    }//=============================================================//☎️

Screenshot 2018-05-13 07.41.26