寒川のアプリ開発者ブログ

美容師しながらアプリ開発してる人のブログです

【Swift4】ToDoリストアプリを作る(4)

新規タスクを追加するところまで実装できました。
セルのテキストビューをタップするとテキストの編集はできますが、キーボードが閉じないので、編集が終わったらキーボードを閉じる処理をまずは実装します。

ソフトキーボードの「改行」表示を「Done」に変更

ストーリーボード上でセルのTextViewを選択し、Text Input TraitsのReturn KeyをDoneに変更します。
キーボードの改行ボタンの表示がDoneに変更されました。

テキストの編集を逐一監視し、改行だったらキーボードを閉じる

class TableViewCell: UITableViewCell,UITextViewDelegate {    //    ←追加

 //    略

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        
        if text == "\n" {
            textView.resignFirstResponder()    //    キーボードを閉じる
                    return false
        }
        return true
    }

テキストの変更を監視し、改行キーが押されたらキーボードを閉じる処理をしています。

Taskの変更を保存する

セルの方でTaskのインスタンスを保持し、テキストの編集やチェックボックスの変更があった時にインスタンスに変更を反映させます。その最新状態のインスタンスをTableViewControllerへ渡し、CoreDataに保存するという流れです。

import UIKit

//    セルの変更があった時にテーブルビューへ伝えるメソッド
protocol CellDelegate {
    func didTaskChenge(task:Task,isTextChanged:Bool)
}

class TableViewCell: UITableViewCell,UITextViewDelegate {

    @IBOutlet weak var checkBox: CheckBox!
    @IBOutlet weak var textView: UITextView!
    
    var task:Task!    //    Taskのインスタンスを保持
    var delegate:CellDelegate!    //    デリゲート
    
    override func awakeFromNib() {
        super.awakeFromNib()
        textView.delegate = self
    }
    
    //    TableViewから実行する初期化のためのメソッドを定義
    func dataInit( _ task:Task){
        self.task = task
        checkBox.setChecked(task.isChecked)
        textView.text = task.text
    }
    
    //    テキストビューのデータソース

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if text == "\n" {
            textView.resignFirstResponder() //キーボードを閉じる
            return false
        }
        return true
    }
    
    //    編集が終了したタイミング
    func textViewDidEndEditing(_ textView: UITextView) {
        print("エディット終了")
        task.text = textView.text    //    インスタンスに変更を加えて
        delegate.didTaskChenge(task: task, isTextChanged: true)    //    TableViewControllerに送る
    }
    
 //    チェックボックスのタップイベント
    @IBAction func checkBoxTap(_ sender: CheckBox) {

        task.isChecked = !task.isChecked
        sender.setChecked(task.isChecked)    //    変更して
        delegate.didTaskChenge(task: task, isTextChanged: false)    //    TableViewControllerへ
    }


    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

    }
}

TableViewController側のセルの初期化処理

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCell
        
        let task = tasks[indexPath.row]
        
        cell.dataInit(task)
        cell.delegate = self

        return cell
    }

cell.dataInit(task)を実行することで、テーブルビュー側では初期化処理をせず、セル側で行うようにします。

TableViewでセルの変更を受け取る

デリゲートを追加してコールバックを受け取り、セーブする処理を実装します。

class TableViewController: UITableViewController,CellDelegate{    //    ←追加

    //    セルからのコールバック
    func didTaskChenge(task: Task, isTextChanged: Bool) {
        if let index = tasks.index(where: {$0.dateUTC == task.dateUTC}){
            tasks[index] = task
            saveData()
        }

    }

tasks配列の中から、dateUTCをIDがわりに当該Taskのインデックスを取得して、セルから送られてきた最新状態のTaskを格納し、saveData()でCoreDataに保存しています。

【Swift4】ToDoリストアプリを作る(3)

肝心要のCoreDataの設定

プロジェクトファイル内に自動的に作られた、アプリ名.Xdatamodeldから
Add Entityをクリックします。
追加されたEntityの名前を、今回は「Task」とします。
Attributesの「+」をクリックして、変数名とデータ型を以下のようにします。

f:id:kentaro198477:20190209004120p:plain
text・・・タスクのテキスト
position・・・タスクのポジション(上から何番目かを表す)
isChecked・・・チェックマークにチェック済みかどうか
dateUIC・・・タスクを識別するためのIDの代わり。現在時刻を記憶する。

空のタスクを、テーブルビューの最下位置に追加する

TableViewControllerに戻り、インポートと、変数の定義と、データベースからTaskの配列を取ってくるメソッドと、まっさらなタスクを追加するメソッドを記述します。
長いです。

import UIKit
import CoreData    //    ←追加

//    略

//    タスクを保存する変数
var tasks:[Task] = []
var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

override func viewDidLoad() {
        super.viewDidLoad()
        
        getData()
        tableView.reloadData()
    }

//    CoreDataからTaskを取得し、tasksに格納・position順に並び替えを行う
    func getData() {
        do {
            // CoreDataからデータをfetchしてtasksに格納
            let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
            tasks = try context.fetch(fetchRequest)
            tasks.sort(by: {$0.position < $1.position})
            saveData()
        } catch {
            print("Fetching Failed.")
        }
    }
    
    //    Taskを追加したり変更した時に呼ぶ
    func saveData(){
        (UIApplication.shared.delegate as! AppDelegate).saveContext()
    }



//    TableViewの、Rowの数を返すメソッドではtasksの要素数を返す
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return tasks.count
    }

 //    空のタスクを新規追加するメソッド
 func addNewStickyNote(){
        
        let task = Task(context: context)
        task.dateUTC = Date().timeIntervalSince1970
        task.position = Int64(tasks.count)
        task.text = ""
        task.isChecked = false
        saveData()
        
        //    tasksに追加し、TableViewに反映させる。追加した付箋までスクロールする
        tasks.append(task)
        tableView.insertRows(at: [IndexPath(row: tasks.count - 1, section: 0)], with: .top)
        tableView.scrollToRow(at: IndexPath(row: tasks.count - 1, section: 0), at: .bottom, animated: true)
    }
    

これで、addNewStickyNote()を呼び出せば、空のタスクが追加されるはずです。
前回作成したフローティングアクションボタンから呼び出してみましょう。
ViewControllerから呼び出すときは、
var tableViewController:TableViewController!
以前に作った変数から呼び出すことができます。

【Swift4】ToDoリストアプリを作る(2)


タスクの新規追加をするためにどのようなUIにするか、ToDoリストアプリにおいて悩みどころです。
今回は、Androidのフローティングアクションボタン風のボタンを右下に配置することにしました。
スマホの操作をしていると、「指を上の方に持っていくのは少々ストレスがかかる」と思い、指の移動を抑えた操作にします。
そう考えるとAndroidのUIは理にかなっていると、今更ながら思いました。

ボタンの配置

ViewControllerの右下にViewを配置し、その中にUIButtonを配置します。
ボタンがContainerViewの下に隠れないようにします。
UIデザインは自由にしましょう。

TableViewのスクロールイベントを拾う

タスクがボタンに隠れないよう、TableViewをスクロールしているときはボタンを隠すようにします。
メルカリの「出品」ボタンの動きを参考にしました。
TableViewControllerに以下を追加するだけで、スクロールイベントを拾うことができます。

   override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        print("スクロール開始")
    }
  
    
    override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView){
        print("スクロール終了")
    }

ボタンを下方向の画面外に隠す・表示するアニメーション

ViewControllerにボタンをアウトレット接続します。
変数名はfloatingActionButtonにしてしまいました。笑

@IBOutlet weak var floatingActionButton: UIButton!

// アニメーションのコード

func showActionButton(){
        floatingActionButton.isHidden = false
        floatingActionButton.center.y += 100
        UIView.animate(withDuration: 0.2, delay: 0.2, options: [.curveEaseOut], animations: {
            self.floatingActionButton.center.y -= 100
        },completion: nil)
    }
    
    func hideActionButton(){
        UIView.animate(withDuration: 0.2, delay: 0.0, options: [.curveEaseIn], animations: {
            self.floatingActionButton.center.y += 100.0
        }) { _ in
            self.floatingActionButton.center.y -= 100.0
            self.floatingActionButton.isHidden = true
        }
    }

スクロール開始でボタンを隠す、終了時に表示

TableViewControllerのスクロールイベントに以下を追加します。

override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        print("スクロール開始")
        (parent as! ViewController).hideActionButton()
    }
  
    
    override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView){
        print("スクロール終了")
        (parent as! ViewController).showActionButton()
    }

ボタンを表示する際に、わずかにディレイをかけています。
念のために、ボタンが隠れるまでにかかる時間と同じだけの時間を空けて、意図しない動作を防ぐためと、アニメーションのタイミング的に心地良いと、個人的に感じたからです。

問題なく動作しましたか?

せっかくなのでFABっぽく影とかをつけてみる

extension UIView {
    func makeUp(){
        self.layer.cornerRadius = 15
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowOffset = CGSize(width: 4, height: 4)
        self.layer.shadowOpacity = 0.4
        self.layer.shadowRadius = 4
    }
}

対象のViewに上記のメソッドを実行し、ボタンや付箋に角丸やシャドウを付加すると、なんとなくそれっぽくなりました。
f:id:kentaro198477:20190208012449j:plain

【Swift4】ToDoリストアプリを作る。

f:id:kentaro198477:20190207011347j:plain

こんな感じのTODOリストを作ってみます。
ポイントは
・コアデータを利用してタスク情報を永続化
・テーブルビューをContainerViewに埋め込む形で利用
です。

何回かに分けてご紹介します。コードについては、拙い部分や、もっとこうした方がスッキリするよ!といったところがあるかもしれません。その際は教えていただけると助かります。
UIの作成に際してのオートレイアウトの使い方については割愛します。

プロジェクト作成

新規プロジェクト作成の際に
Use Core Data
にチェックを入れます(デフォルトでチェック入っている)。
これでCoreDataを簡単に利用できるようになります。

TableViewControllerをContainerViewに埋め込む


ストーリーボード上で、メインのViewController(以下ViewController)にContainerViewを画面いっぱいに配置します。
自動的に作られるViewControllerを選択して、deleteを押して削除します(ストーリーボード上から消え去ります)。
ストーリーボード上にTableViewControllerを配置。
ContainerViewから、controlキーを押しながらTableViewControllerまでドラッグし、ポップアップからEmbedをクリックします。

f:id:kentaro198477:20190207011305p:plain
ContainerViewにTableViewControllerを含めることができました。

TableViewではなくTableViewControllerを使うのは、大きな利点があります。それは、セルに後ほどTextViewを配置しますが、これのテキストを編集しようとタップすると、TextViewがキーボードに隠れてしまうことがあります。TableViewControllerであれば、TextViewが隠れないように自動的にスクロールしてくれます。

TableViewControllerのセルのデザイン

ToDoリストっぽい、チェックボックスとテキストのデザインを作ります。
SwiftにはチェックボックスのUI部品がないので、まずはこれを作ります。
チェックボックス用のチェック済み、未チェックの画像を用意し、Assetsフォルダに投げ込みます。
名前はそれぞれ、checkedとuncheckedにしました。

New File…から、Cocoa Touch Classを選び、UIButtonを継承したCheckBoxというファイルを作ります。

import UIKit

class CheckBox: UIButton {

    // Images
    let checkedImage = UIImage(named: "checked")! as UIImage
    let uncheckedImage = UIImage(named: "unchecked")! as UIImage
    
    // Bool property
    var isChecked: Bool = false {
        didSet{
            if isChecked == true {
                self.setImage(checkedImage, for: UIControl.State.normal)
            } else {
                self.setImage(uncheckedImage, for: UIControl.State.normal)
            }
        }
    }
    
    override func awakeFromNib() {
        self.addTarget(self, action:#selector(buttonClicked(sender:)), for: UIControl.Event.touchUpInside)
        self.isChecked = false
    }
    
    @objc func buttonClicked(sender: UIButton) {

    }
    
    func setChecked(_ check : Bool){
        isChecked = check
    }
}

ボタンを押した時にチェックマークを反転させるようにはしません。

PrototypeCellsにCheckBoxと、TextViewを配置する

CheckBoxを置くには、UIButtonを配置してから、クラスをCheckBoxに変更します。
ここら辺は、自由にレイアウトしてください!

テーブルビュー情報

UITableViewControllerを継承した、TableViewControllerというファイルを作ります。
ストーリーボード上のUITableViewControllerのクラスをTableViewControllerに変更します。
ViewControllerから、TableViewControllerのメソッドを呼べるように、TableViewControllerの参照を保持しておきます。

import UIKit

class ViewController: UIViewController {

    var tableViewController:TableViewController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let tableViewController = segue.destination as? TableViewController {
             self.tableViewController = tableViewController
        }
    }
}

カスタムセルを定義する

UITableViewCellを継承したTableViewCellというファイルを作ります。
ストーリーボード上のPrototype CellのクラスをTableViewCellにし、Identifierを「Cell」にします。
TableViewCellに先ほど配置したチェックボックスとテキストビューを、アウトレット接続します。

@IBOutlet weak var checkBox: CheckBox!
@IBOutlet weak var textView: UITextView!

TableViewControllerに戻り、以下を追加します。

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCell
  
        // Configure the cell...

        return cell
    }

withIdentifier: “Cell”にし、as! TableViewCellを付け加えています。

一息ついて、ひとまず動作確認

    override func numberOfSections(in tableView: UITableView) -> Int {
               return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        //    後で直してください
        return 1
    }

    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCell
        
        cell.textView.text = “適当に長い文章を入れてみます”

        // Configure the cell...

        return cell
    }

正しく表示されましたか?
TextViewで長文を表示する際にスクロールさせないようにするには、プロパティのScrolling Enabledのチェックを外します。スクロールバーが非表示になり、全ての文章が表示されるようになります。

CoreDataを使う

CoreDataを使う

プロジェクト作成時に、use CoreDataにチェックを入れる。
プロジェクト名.xcDatamodeldから、Add Entitiesをクリック。
ENTITIESのモデル名を定義する(今回はDataとしています)
Attributesに、利用するデータ型を定義する。

import CoreData

インポートします。

var data:[Data] = []

func getData() {
        
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        do {
            
            let fetchRequest: NSFetchRequest<Data> = Data.fetchRequest()
            data = try context.fetch(fetchRequest)
            
         } catch {
            print("Fetching Failed.")
        }
    }

dataにData型の配列が入ります。

保存する。

let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        let data = Data(context: context)
        data.propaties = “value”    //    プロパティに値を入れたり
        (UIApplication.shared.delegate as! AppDelegate).saveContext()

削除する。

let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        
context.delete(data[0])    //    削除するオブジェクト

UIApplication.shared.delegate as! AppDelegate).saveContext()

【part5】初めてのヒッチハイク旅!!

 国道20号線沿い、信号を渡ると”瑰泉”というポイントで降ろしてもらい、私のヒッチハイクは終わりました。
今の時刻は午前4時半。寒川からここ石和温泉まで約15時間の旅。瑰泉の建物の光が夜空を明るくしています。
www.yu-kaisen.jp

kojiko-android.hatenablog.com

ゴールに到達

 スタートした時は先が見えなかったヒッチハイク旅も、何台もの車に乗せてもらい、移動距離が増えるほど、点が線になって行くように感じました。少し大げさなようですが、旅が進むほど不安が減少し自信がついてきます。苦境に陥っても「必ずたどり着く」という気持ちになります。というより「まぁ、ゴールできるっしょ!」という感じの方が近いかな笑。

 瑰泉は24時間営業で、雑魚寝スペースがあります。これは、2台目のトラックの運転手さんに教えていただきました。山梨に着けば、ビジネスホテルかカプセルホテル、漫画喫茶、カラオケの一つくらいはあるだろうと思っていたのは余りにも浅はかでした。先のアドバイスが無ければ野宿をしていたかもしれません。ちゃんとした寝床にありつけたのは本当に有り難いことでした。
 雑魚寝スペースに転がり落ちるようにして横になりました。やや硬いマットレスと枕も十分な快適さです。掛け布団はなさそうなので、タオルと上着をかけます。前日のスタート時点から今までが鮮明に思い出されますが、15時間しか経っていない事に逆に驚きました。濃密です。出会った人々全員に感謝しながら寝たのは、決して大げさに言っていません。翌日は施設の温泉に入り、朝食を食べ、ハンモックに揺られながら(今頃他のスタッフたちは、ハワイでハンモックに揺られているのだろうか)、今日1日の予定を考えました。あとは、普通の観光をしました!

f:id:kentaro198477:20180912003752j:plain
様々なブドウ。お腹が膨れたため”ほうとう”はまたの機会に

ヒッチハイクで得たもの

 半ば勢いだけで決行したヒッチハイクは、無事に終わりました。様々なブロガーがヒッチハイクについての記事を書かれています。自分も読ませていただきました。中にはヒッチハイクで日本一周された方もいらっしゃるので、ヒッチハイクのやり方だったり注意点は、そのような上級者の方の意見が参考になると思います。ここでは、あくまで私なりに感じた事を書いていきます。
 

  • 困難な状況を打開する力がつく

 深夜のサービスエリアに降り立った時、一瞬途方に暮れましたが状況を検証し「今の状況は”悪い”。どうにかしなければ」という思いが立ち、すぐに行動に移りました。車でしか来ない場所に、生身で居る。この苦境から逸脱するには?結果、片っ端から声をかけるという方法を取りましたが(笑)、日常生活や仕事で困難なときに、それを乗り越える力がつくと思います。

  • 人や、様々な事象に感謝の気持ちを持てる

 人々に対しては言わずもがなですが、インフラが整っているという事に有り難みを感じました。車の税金や有料道路について煩わしいと思っても、道が続いていない事には移動もできません。旅の趣旨ではないですが、山梨に行きたいのなら電車を利用して3時間ほどで着いてしまいます。震災などで停電になった時に電気の有り難みを感じますが普段はさほど感じないように、当たり前なことが当たり前ではないのだと気付かされました。

  • 様々な職の人と出会える

 普段関わりを持たない職種の人と話すことができます。ヒッチハイク関連の記事でよく言われていますね。私は美容師なので様々な方とお話しをしますが、ヒッチハイクの場合は出会いの状況が特殊なぶん、不思議な空気感の中でする会話は面白いものです。

  • 目的達成までの一本道を進んだという成功体験ができる

 自分で目的地を決め、それまでの道のりを考える。全ての意思決定を自分でする。その結果は自分に降りかかる。他の誰の責任でもない。目的地に着いた時、意思決定をした点が線になる。人生でそのような体験はなかなか容易ではないですが、ヒッチハイクなら短時間に凝縮してそのような成功体験が得られると思います。人間の脳はイメージと実際に体験したこととの区別ができないそうです。これはスポーツにおいて大切な事ですが、一連のプロセスは様々なところで役立つのではないでしょうか。じゃあヒッチハイクもイメトレでいいじゃんというとそうではなく、あなたが今後達成したい目標への道のりを、より明確にイメージできるのでは?という事です。

  • メンタルが鍛えられる

 これもよく言われますね。私も高校生に後ろ指を指されたり、車の中から笑われたり、睨まれたりとメンタルを削られる場面は多々ありました。ですが、窮地に追い込まれるとメンタルどうのこうの言っている場合じゃ無くなります。そのうち、そのようなネガティブな反応なんて、旅で得られるものの価値に比べたら小っぽけに感じるようになります。

  • 話のネタになる

 私は休み明けからお客様と会話するときは、ほぼほぼ今回の旅の話をしています。かなりの確率で「すごい!」と言われます。「ハワイ行くより良い経験ができたんじゃない?」とさえ言われる事もあります。そもそものきっかけが、みんながハワイ行ったら帰国後はその話題ばかりになる、自分も何かネタを作らなきゃ、というものでした笑。

ヒッチハイクの危険性

 メリットばかりを挙げましたが、危険性も伴うのは事実です。全くの見ず知らずの人の車に乗り込むわけですから、100%安全の保証はないのです。心の優しい人だけがふるいにかけられて止まっているとは限りません。あなたが腕っ節が強いからと言っても然りです。車内は半密室だということは絶対に忘れてはなりません。逆にヒッチハイカーを乗せる場合もです。カージャックというと非現実的に聞こえますが、乗せる際は手荷物検査くらいはしても良いと思います。

ヒッチハイクをしようかな〜と思っている方へ

 決められたルートをトレースする旅行ではなく、自分の判断によって、吉と出るか凶と出るかわからないが自分を信じて続いてゆく旅は、私にとって価値のあるものとなりました。3時間もあれば着く距離を、15時間かけてでも行った事に意味があります。その15時間は驚くほどあっという間で、ぎゅっと凝縮されています。宝物をたくさん発見できた旅でした。
 それでもヒッチハイクを人に勧めにくいのは、やはり危険性が伴うという事でしょう。何かを得るためにリスクを背負うのは悪いことではないですが、ヒッチハイクのリスクは、身の危険です。私はたまたま良い人に巡り会えただけかもしれません。

 ですので、ヒッチハイクはオススメしません笑

 成功体験を積むには、いくらでも方法はあります。たとえば歌手を目指しているとして度胸をつけたい場合、ヒッチハイクよりも路上で歌った方が得られる経験値が高そうです。
 
 今回乗せてくださった方には最高の感謝の意を表明します。その上で、次のことを述べます。
車に乗せる事だけが、人の優しさの本質ではありません。車を持っていない人だって、胸いっぱいに染み渡る優しさを持っている人もいるはずです。人の優しさに触れる機会として見た場合、ヒッチハイクが最善の方法とは限りません。表に出ていないだけで、見返りを期待したり、下心を潜めている場合も無いとは言い切れません。
 ただ、海老名で立っていた時にスポーツドリンクを差し入れて下さった方は、素で優しい方だと思いました。

 以上が、私の見解です。
ヒッチハイクに挑戦される方は、くれぐれも怪我のないようにお気をつけください!

さいごに

 今回の私の身勝手な旅の道中、関わった全ての方に心から感謝しています。
最後までお読みいただきありがとうございました。

【part4】初めてのヒッチハイク旅!!

目的地の山梨、甲府までの最後のサービスエリアに到着したのは午前2時過ぎ。停車中のトラックは、エンジンはかかっているものの、ウィンドウはカーテンが閉じられています。

kojiko-android.hatenablog.com

片っ端から声を掛ける

 不思議と、焦りは無かったですね。なんとかなるという、前向きな気持ちと、ここまで来れたんだという自負がありました。自分の置かれた状況を見て、さぁ、どうするかな!という感じです。ミッションは、甲府方面に行く車を探すこと、同乗の許可を得ること、この二つです。後者は、交渉によって成功率は変わります。自分が、スーパースターやアイドルだったら難易度は下がるでしょうが、そうではないので、最善の方法と思われる”心から切実にお願いする”ことにしました。起きている人に片っ端から、自分は甲府に行きたいんですと言って回りました。

 まずは、配送業ではない一般の方にあたってみました。駐車してトイレに行き、出てきたところに声をかけますが、ほぼ全員が「そっちの方には行かないですね」といった返答。賢明な回答と思います。どこの誰だか分からない人など乗せたくありませんよね。まして午前2時、逃走中の犯罪者かもしれません。乗せてドアを閉めた途端、ナイフを突きつけ、財布を奪いそして停車してある自分の車に飛び乗って逃走、なんて事も無くもない。
短時間で自己証明をすることの難しさを知りました。アイドルがオーディションの限られた時間でアピールをし、グランプリを取れるのは、それだけの理由があったのですね。

 談笑している、二人組の運送業者のドライバーに声を掛けました。交渉に有利な雰囲気を壊さぬよう、笑いも交えた感じで挑むも、山梨では降りないとのことでした。ただ、やはり運送業の方はヒッチハイカーに慣れているという印象。そして、良いアドバイスをもらいました。「甲府に行くなら、”山梨ナンバー” か”静岡ナンバー”の車に声を掛けないとダメでしょー」
 ヒッチハイク初心者で、高速もほとんど乗ったことがない私にとっては、それすら気づきませんでした。笑
それからは、山梨ナンバーと静岡ナンバーに絞って探し歩きます。それなりに停車しています。カーテンは閉じているがエンジンはかかっている車の付近で、起きるまで待つなんて事もしました。なかなか巡り会えませんが、それでも手当たり次第よりは、目的に近づいている手段と思えます。

 雨が降ってきました。幸い気温はちょうど良くて、濡れても問題ない感じでしたが、さすがに眠かったです。風の入らない場所で寝るという選択肢も出てきます。くどいですが、意思決定するのは自分です。後退の道を選べば、このサービスエリアで降りたところから自分の判断は間違っていたのか、という結果になりかねません。孫子の兵法、買ったけどまだ読んでなかった・・・。読んでたら、こういうときの判断に強くなっていたかもしれない。

孫子の兵法 (知的生きかた文庫)

孫子の兵法 (知的生きかた文庫)

寝ても、結局朝になったら同じことをするし、出勤時間は、皆ピリピリしてるかもしれない。朝になって風邪を引いていて、首や肩が痛い状態でヒッチハイクは、もしかしたら絶望的ではないか、と判断しました笑。

結果が欲しい

 判断が正しかったかどうかは、結果が出たときに判断できる。今私は、エンジンがかかっていて、カーテンは閉じているトラックの付近で、そのカーテンがシャッと開くのを待っていたところ、私の後ろを山梨ナンバーのトラックが通り過ぎて行きました。「貴重な山梨ナンバー・・・」と思いました。この結果について、私は待つ場所を間違ったのかもしれません。でも、そのトラックはサービスエリアのガソリンスタンドに入って行きました・・・。

 今日2回目のダッシュ!笑

運転手はモップを使って窓を拭いています。遠くからわかったこと、このドライバーさんもスキンヘッドだということ。走りながらもこの2時間を振り返り、断られることに慣れつつあるが、声を掛けないことには始まらない。
「すみませーん!」と呼びかけ、すがるような思いで事情を話すと、

「いいよー、おいでー!」

 神が現れたと思いましたね!
拍子抜けするほど軽い感じの口調で、後輩を大事にしていそうな方という風に見えました。
行き先は、甲府ではないけど20号線沿いを通り、途中に”瑰泉”という24時間営業のスーパー銭湯があります。そこでは雑魚寝ができ、もちろん風呂もあり、石和温泉駅も近い。甲府までは、電車でいうと2駅の距離。ゴールです!

 海老名から乗せてもらった方よりも、かなり飛ばす運転。それが疲れも吹き飛ばすようで心地よかったです。会話も楽しく、途中後輩らしき方から着信があり、応対を聞いていると、兄弟と話しているかのようなやりとり(会話はハンズフリーでした、たしか笑)。第一印象の通りです。

 90キロもの距離を、あっという間に到着。しっかりと感謝の気持ちを伝え、降りると、目の前に”瑰泉”が光っています。先ほどのサービスエリアよりも、夜空が広く見えました。

part5へ・・・。
kojiko-android.hatenablog.com