のらぬこの日常を描く

ノージャンルのお役立ち情報やアニメとゲームの話、ソフトウェア開発に関する話などを中心としたブログです。

一人旅愛好家のための宿検索サイトを作ってみた

どうものらぬこです

 

このブログ書くのはかなり久しぶりな気がいたします。

 

先日、「どこかの温泉地で」とか「金曜、土曜、もしくは祝前日のどこか」、などのゆる~い条件で、一人で泊まれる旅館、ホテルが検索できるサイトを立ち上げてみました。

一人で泊まれる宿検索|ソロ旅ねっと

 

「禁煙のお部屋」「無料Wi-Fi付き」「和室」などの細かい条件指定はできませんが

7~8週間先までに空室のある一人宿泊おkの宿を、宿泊予定日、旅行先の候補地、「鉄道駅の近く」「温泉付き宿」「夕食付プランあり」の3つの条件、自由に組み合わせて、簡単に探すことができるようになっています。

 

f:id:noranuk0:20190621143732p:plain

f:id:noranuk0:20190621143753p:plain

 

温泉地にちょっと行ってみたいけど、宿探すの面倒くさいし、草津温泉と熱海温泉は少し前に行ったなー。今回はそれ以外の温泉行ってみたいけど、どこにどんなのがあるのかよく知らない、電車も通ってるのかわからんし、、、っていう、僕みたいな方にも、なるべく使いやすいサービスを目指しております。

 

ご興味ありましたら、一度触ってみてください。

 

ちなみに

無料です。サイト利用にお金は絶対にかかりません。ユーザ登録不要です、というかそういう機能はありません。個人情報を集めるようなこともしてません(PV数くらいは見たいので、Google Analyticsだけは入れています)。裏でこっそり仮想通貨マイニングもやってません。無限アラートダイアログも出ません。

 

作った経緯

さて、ついでなので、どういうことを考えて、このサイトを作ろうと思ったのかもお話したいと思います。

 

ここ数年、一人旅というジャンルにハマっております。

 

連休を使ったり金曜日に有給とったりして、毎年何度か、温泉街を中心に旅行に行き、温泉に浸かりひたすらダラダラして、普段食べることができないような美味しいお食事とお酒(割と日本酒限定)を頂きつつ、至福の時を過ごすことを生きがいの一つとしております。

宿探しって意外と面倒くさい 

余談ですが、僕が宿に求めることは大体以下のような感じです。

  • 食事つきの宿*1
    • ごはんが美味しいこと
      • 懐石/会席料理って言葉には心惹かれます
      • 大外れを引いたことが過去一度ありましたが・・・
      • 夕食がビュッフェ(バイキング)な宿・ホテルは面倒くさいのでご遠慮したい
      • お部屋食がよいけどあまりこだわらない。館内レストランで一人フレンチとかもあるし。
    • お食事と一緒にお酒が頼めること
      • 会社絡みの飲みないなんて存在自体無くなればよいと思っているし、普段一人でお酒を飲むという習慣もないのですが、旅行行ったときはちょいちょい飲んでいます。
  • 温泉付きであること
    • 源泉かけ流しという言葉には惹かれます。
    • 露天風呂は眺めがよければいいのですが、ただ外にあるだけっていうなら特にいらない。寒いし。
  • 駅から徒歩圏内であること
    • 徒歩30分以内なら、急な坂とかなければ大体おk。
    • 駅から歩いてきました!というと驚かれることも多々。徒歩25分くらいで驚くなや、と思う。
  • 価格は1万円~頑張って2万円

昭和の時代、まだインターネットが存在しなかった頃は、「るるぶ○○」みたいな本を買ってきて、1件1件電話して空室状況を聞いて回るという、今から考えれば気の狂いそうなことをやっていたような気がいたします(当時は僕もまだ小学生だったし、それをやっていたのは父親でしたが)。

が、今の時代はインターネットがあります。

JTB」「じゃらん」「楽天トラベル」「Booking」等等、様々な宿検索サイトが立ち上がっており、日付と目的地さえある程度決まっていれば、比較的簡単に、旅館、ホテルを探すことができます。

例えば、「6月7日 大人一人予算1万円から1万5千円、夕食+朝食付き、源泉かけ流し温泉付き、部屋は禁煙、Wi-Fi付きの伊香保温泉の宿泊施設」などはお手の物です。

 

ただ、「ここ1か月くらいの金曜日or土曜日に、電車で行けそうなどこかの温泉地に、2万円くらいの予算で一人で泊まれる温泉旅館」みたいな条件で宿を探すのは意外と面倒くさかったりします。

 

友達同士で旅行に行く場合、事前に日程を調整して、行きたい場所もある程度絞ってから宿探しを始めることが多いと思うので、どこかの土曜日、とか、どっかの温泉地~、みたいな適当な条件での宿泊施設検索は、あまり需要がなかったのかもしれません。

 

今後の予定

今後やりたいなー、と思っていることを書いておきます。

  • 施設周辺の地図をもうちょいどうにかしたい
  • 価格による絞り込み・ソート
  • なるべく長期間の空室状況が閲覧できるように
  • バス停留所の情報も入れたい
  • 温泉地巡り支援(例えば、ある温泉地から1時間半以内で行ける温泉地を出すとか)

温泉地巡り支援はやりたいのですが、個人で(サーバ維持費用以外のお金をかけずに)実現するのは難しそう。。。

 

 というわけで、今回の記事はここまでです。

 

もう少し細かい話はこちらから。

qiita.com

 

お読みいただいてありがとうございました

 

*1:草津温泉は温泉付きなら素泊まり宿でおk。京都とか食事つき宿泊施設の物価が高いところも同様。

AdMobサンプルの丸コピは止めて、アプリ起動時間を少しでも短縮する方法

どうものらぬこです。

 

今日はandroidアプリ開発の話です。

 

2014年の夏ごろにリリースした「appSelector.web」というアプリの Ver.2.0を先日リリースさせていただきました。

満を期してリリースしたはずの Ver.2.0 で、android 8.0以降で動作しないという大罪を犯したりと、ちょっとやらかしてしまいましたが、現在はしっかりと安定したものがリリースされているはずでございます。

 

https://play.google.com/store/apps/details?id=com.house.noranuko.easyapplauncher

 

さて、このアプリ、収益源は広告収入となっており(インストール数が少ないので収益額は尺取り虫の涙程度なんですけど)、アプリを立ち上げると下の方にバナー広告がでーんっと居座っているような形になっております。

 

ちなみに、広告配信は AdMobを利用させていただいております。 

一応今回は開発向け記事なんですが、AdMobの利用開始手順等は、特に書きたい話でもないので、このへんはサクッと省略させていただきます。

 

AdMobの実装サンプルサイトに掲載されている初期化コードはこんな感じです。


public class MainActivity
    extends AppCompatActivity
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        MobileAds.initialize(this, "ca-app-pub-1234567890");
        AdRequest adRequest =
            new AdRequest.Builder()
            .addTestDevice("1234567890ABCDEF").build();
    AdView adView = dataBinding.adBanner;
    adView.loadAd(adRequest);
}

 

パブリッシャーIDを自分のアカウントと紐づいた値に置き換えるだとか、AndroidManifest.xmlになんか書かなきゃいけないだとか、build.gradleに依存関係追記しないといけないだとか、やることはほかにもいくつかありますが、Javaコードの実装はこれだけです。


公式サンプルも大体こんな感じだったと思います。

 

広告を表示するための下準備は非常に簡単なのですが、最初に必ず呼び出さなければならないMobileAds.initialize(); のメソッド呼び出し、こいつが結構重いのです。

実行時間を計ってみたところ、僕の環境では約0.8秒から1.0秒、さらにその下の AdViewの初期化も合わせると1.5秒くらいかかっている印象です。

もちろん、起動時に行う初期化処理は広告表示のための処理以外にもいろいろあるわけで、「appSelector」の場合、起動に約2秒以上はかかっていました。

 

ユーザがアプリを立ち上げたら、すぐに画面が表示され、すぐに操作できる状態にしたいようなツール系アプリで、起動に2秒は結構致命的かなと。

 

ということで、どうにかする方法を考えました。

 

起動時間を短縮したい。

一番時間がかかっているのは広告の初期化。

onCreateから広告初期化ロジックを削除して、代わりに AsyncTaskLoader あたりでバックグラウンドで実行。loadFinished で adView.loadAd() すればいいんじゃないかな?

 

やってみた。


public class MainActivity
    extends AppCompatActivity
    implements LoaderManager.LoaderCallbacks {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getLoaderManager().initLoader(0, new Bundle(), this);
    }
    
    public static class MobileAdsInitializer
            extends AsyncTaskLoader {

        public MobileAdsInitializer(Context context) {
            super(context);
        }

        @Override
        public Void loadInBackground() {
            MobileAds.initialize(
                getContext(), "ca-app-pub-1234567890");
            return null;
        }

        @Override
        protected void onStartLoading() {
            forceLoad();
        }
    }

    @Override
    public Loader onCreateLoader(int i, Bundle bundle) {
        return new MobileAdsInitializer(this);
    }

    @Override
    public void onLoadFinished(Loader loader, Void v) {
        AdRequest adRequest =
            new AdRequest.Builder()
            .addTestDevice("1234567890ABCDEF").build();
        AdView adView = dataBinding.adBanner;
        adView.loadAd(adRequest);
    }

    @Override
    public void onLoaderReset(Loader loader) {
    }
}

 Loaderの実装がかなり適当で恐縮ですが、大体こんな感じです。

 

結果。

 

ログを取って検証してみました。

f:id:noranuk0:20181127230556p:plain

Application.onCreate の処理が開始された時間から、MainActivity.onCreate 処理の完了時間の差分を取って初期化処理の実行時間を測定してみたところ、起動時間が 2.1秒から0.6秒に短縮されたことがわかります。

 

アプリ起動後、広告が表示されるまでに若干時間が空いてしまったりといった弊害(?)もありますが、起動時間を短縮させることによってユーザビリティーは向上したと考えてよいと思います。

 

今回は、アプリケーションの主要機能とは無関係の個所の処理(広告表示まわり)を遅延することで、アプリの起動時間を短縮してみたお話でした。

 

今回の記事がどなたかのご参考になりましたら幸いです。

 

 

 

 

お読みいただいてありがとうございました。

一人住まいだけどミーレの食洗機を購入してとても満足した話

どうものらぬこです。

今回は食洗機のお話です。

今の家に住み着いてから約7年。

前々から「ほしいなー」と漠然と思っていた食洗機を、先日ついに導入しました。

f:id:noranuk0:20181014145711j:plain

写真に写っている白い大きな機械が、今回導入した食洗機です。

僕が今回購入したのは、ミーレというドイツのメーカが出している幅60センチ、高さは81センチのビルトイン型と呼ばれているタイプの食洗器です。

食洗機には、流し台の上に置くタイプの据え置き型と、システムキッチンのキャビネットにはめ込むタイプのビルトイン型の2種類のタイプがあります。

価格で考えるなら、と作りがシンプルで、設置工事も簡単な据え置き型が安価ですが、一度に洗える容量はビルトイン型のほうが大きいです。

ビルトインタイプ食洗機は、国内からはパナソニックリンナイから出ており、僕も最初は国内メーカーの2択で検討していたのですが、諸般の事情でどちらのメーカーもボツ案となり、最終的にミーレを選択することにしました。

ミーレ・ジャパン | ドイツのプレミアム家電ブランド

今回の記事では、どうして食洗機を導入しようと思ったのか、なんで国産を選ばずに海外製を選んだのか、などのお話を書いていきます。

突然ですが、数ある家事の中で一番嫌いな家事は洗濯でした。

「大嫌いな洗濯という苦行から解放されたい」という願いは、1年半ほど前に「ドラム式全自動洗濯機」を購入することにより、ほぼ完ぺきに叶えることが出来ました。

ドラム式洗濯機の記事も書いております。ドラム式洗濯機がどれほど素晴らしいか知りたい、欲しいけど迷っています、という方がいらっしゃいましたら、よろしければご覧になってください。 noranuk0.hatenablog.com

ドラム式洗濯機の記事でも軽く触れたのですが、洗濯の次に嫌いなのは食後の後片付けです。

鍋や食器をキッチン流し台でじゃぶじゃぶ洗う、アレです。

嫌いな理由

特に夏、洗い物が面倒くさくて少しサボっただけで、すぐにコバエが沸く。 台所をコバエが飛び回ってるのを見ると、それだけで生きていくのが辛くなる。

特に冬、台所寒いし、水が冷たくて洗い物とかやってらんない。 我慢しろとか根性が足りんとか何その昭和人的思考

主に精神的、心理的な理由により洗い物がたまってくると、色々絶望してくる。

気が付くとキッチンが腐海化している。

そこから徐々に腐海が広がってくる。

そう、これが悲劇の始まり・・・

さらにもう一つ、ご飯を食べ終わって眠りにつくまでの残り少ない時間をダラダラして過ごしたいのに、洗い物という無賃金労働をしなければいけないのは苦行でしかありません。

食洗機の導入を考えられている方に「何故欲しいのか」と聞けば、大体似たような答えが返ってくるのではないかと思います。

何故今まで買わなかったのか

転居してから7年。購入に踏み切ろうと思えば買える機会はいくらでもあったはずなのですが、なぜ今まで買わなかったのか?

一つ目は予算の問題。

食洗機を新規で導入する場合、ビルトインタイプのものを後付けで設置する場合には約20万円程度のお金がかかります。

価格比較サイトなどを見ると、「標準取り付け工事費込みで10万円!!」とか掲載されていますが、その金額はおそらく「電気工事も給排水管工事も完了していて、後は食洗器をはめ込む(もしくは古いものと入れ替える)だけ」のお値段です。 何の準備もできていない状態から後付けで食洗器を設置する場合、給排水管工事だの電気工事だのその他もろもろ費用合わせて15万以上はかかってくると思われます。

ただ、僕の場合に限って言えば、ゲーム機買ったり、モバイル端末買いまくったり、帰り道ちょくちょく買い食いしたりで、無駄遣いも結構しているので、20万程度なら、それらをなるべく我慢していれば、捻出できたタイミングは十分にあったはとは思います。

二つ目。費用対効果が未知数という問題。

どちらかというと、メインはこちらです。

食洗機を購入した場合、食器を洗う手間は削減できますが、食洗機のメンテナンス(食洗機を洗う手間)という新たな時間的なコストが発生します。

さらに、食器によっては食洗機で洗なかったり(材質の問題)、大きな鍋などはそもそも食洗機に入らないということも考えられます。

せっかく高いお金を払って食洗機を導入したのに、鍋は手洗いしなければならないとか、なんかもう意味わかんないですよね。

それでもやっぱり欲しかった訳

  • 家でご飯を作ろうとする
  • → 作って食べた後に、洗い物をしなければならないと考える
  • → 洗い物が嫌い
  • → ご飯を作るのをあきらめてしまう

結局のところ、このスパイラルをいい加減解消したかったのが大きかったのかなー、と思います。

購入を決意 ~施工完了までの長い道のり~

今年の7月の終わり頃から製品選びをはじめ、10月初旬にようやく施工が完了しました。

約2か月半はかかりましたが、よい選択ができたと思っております。

冒頭でも書きましたが、購入したのは、ミーレというドイツのメーカーの食洗機です。

国産の食洗機と比べると容量が大きく、また国産のものより省エネらしいです。

ただし、国産のものと比べると価格は高いです。容量が全然違うので価格だけでの単純比較はできないのですが、それでも値段だけで比べてしまうと3倍以上の開きがあります。

製品の選択

話を7月末ごろに戻します。

購入対象の食洗機の条件として必須だったのは、ビルトインタイプの大き目サイズの食洗機でした。

大きさの都合で洗えないものが出てくるのは嫌だったので、大き目サイズという条件も必須でした。

さらに、調理スペースが狭くなってしまうのが嫌で、据え置き型は全く候補に入れていませんでした。

大き目サイズとなると据え置き型では厳しいので、この条件からも、選択肢はビルトイン型に限られることになります。

ちなみに、既設のシステムキッチンに後付けでビルトイン型の食洗機を設置する場合、システムキッチン下のキャビネットの一部を壊し、そこに食洗機を嵌め込む形になります。

我が家の場合には、幅60センチの引き出しがあったので、そこを解体して、空いた部分に食洗機を埋め込むことが可能なはず、と考えました。

f:id:noranuk0:20181014142913p:plain

当初は、パナソニックリンナイの二択で迷っており、ミーレも頭の片隅にはありましたが候補としては殆ど全く考えていませんでした。

ですが、実際にカタログを見たり、ウェブサイトを眺めたりしつつ、国内メーカーの食洗機の情報を集めてみると残念な事実がわかりました。

パナソニックリンナイも、日本の狭いキッチンに配慮してなのか、幅45センチ、高さも40センチ程度のものが主流だったんです。 しかもこれは外寸のサイズなので、内寸はもう二回りほど狭いと思われます。

ウェブで検索して体験談や使用レポートなどを読んでみても、やはり、鍋は入らないため結局手洗いしてますだとか、食器を全部入れるのは割と工夫して配置しなければならないという趣旨の記事がちらほら出てきます。

時間を節約したいから食洗機を買いたいのに、そういう職人技スキルを発動するために時間を使いたくはないです。

結局わかった事は、少なくとも普及型サイズの食洗機に、洗い物全てを請け負ってほしい、魚を焼くための網や鍋、まな板などなど、食後の洗い物全てをお任せするという事を求めるのは酷であるという事でした。

大き目サイズのビルトイン食洗機はあるのか?

国内メーカー産の大き目サイズのビルトイン食洗機も、探せば一応見つかります。

まず、パナソニックからは幅60センチの食洗機が出ています。

現行機種一覧・機能比較 | ビルトイン食器洗い乾燥機 | Panasonic

ただし、幅60cmタイプの食洗機、最終機種の発売日が10年以上前で、新製品が出る気配も今のところはなさそうです。また、幅は広いのですが、深さはそれほどありません。
それでもネットの評判は上々のようです。

2020年追記) パナソニックのワイドタイプなビルトイン食洗機、新製品が出ていたようです。 sumai.panasonic.jp

リンナイからも出ています。

ただし、リンナイ製の幅60センチタイプは既設食洗機からの交換専用機種のようで、既存システムキッチンへの後付けには対応していないようでした。

その代わり、幅は45センチですが、フロントオープンタイプで高さが60センチほどの、比較的大きな食洗機が販売されています。

こちらも使いやすさでは定評のようでした。

食器洗い乾燥機 洗剤洗浄タイプ:フロントオープンタイプ RSW-F402C - リンナイ

食洗機をはめ込んだ時に出来る空きスペースは、いずれの食洗機を選んだ場合も専用キャビネットをはめ込むことで、スペースも有効活用することが出来るようになっています。

f:id:noranuk0:20181014142917p:plain

これで購入商品は2つに絞られました。

いざ、見積もりへ

候補が決まったので、以下の3社さんに見積もりを依頼しました。

あと、候補としてはあまり考えていなかったのですが、せっかくなのでミーレのショールームにも見学に行ってみることにしました。

見積もりの結果は・・・

今の住居を購入したハウスメーカーの提携会社

まずは、今の住居を購入したハウスメーカーの提携会社にお伺いを立ててみました。

が、現状備え付けのシステムキッチンキャビネットが廃盤のため、食洗機の設置は不可能。設置するのであれば、システムキッチンのキャビネットをまるごと交換しないといけないと言われます。

見積価格は55万弱。

心の中で「死ねよ」と思いました。

とある一括見積サイトで見つけた業者

次に、とある一括見積サイトで見つけた業者さんにご訪問いただき、購入予定の機種をお伝えした上で、見積もりを取ってもらいました。

結果、パナソニック60センチタイプ、リンナイ45センチタイプ いずれのタイプも設置は可能。費用は、取り付け費用、配管、電気工事費、追加キャビネット込みで30万前後。 ちょっと高い気もするけど、うん、まあそんなもんだよね、という見積内容です。

ビックカメラ

最後に、ビックカメラさんにもお越しいただき、見積もりをお願いしました。

ところが、

見積もりに来ていただいた方から

ある衝撃の事実

を告げられました。

60センチの引き出しを壊してそこに食洗器を設置する算段だったのですが、内側の仕切り板が邪魔をして幅が59センチしかとれない。

したがって、幅が1センチ足りず、残念ながらパナソニック60センチタイプは設置不可。

リンナイ45センチタイプの設置は可能だが、食洗機入れたら隙間が14センチしか取れないので、15センチキャビネットも設置できず、この部分は隙間が空いてしまう、とのこと。

f:id:noranuk0:20181014142924p:plain

1センチ足りない問題の話を聞いたときは「まじかよ」と思いましたが、確かにおっしゃっていたことはもっともです。

最初の工事業者さんからは設置可能との判断をもらったのですが、これは判断ミスだったのでしょうか。今となってはわかりません。

お見積価格は設置、配管、電気工事費込みで20万前後。キャビネットが付かない(入らない)ので、その分最初の業者さんより安くなっている感じです。価格的には妥当なところですね。

ミーレ

せっかくなので、ものすごいセレブなイメージのミーレも検討してみることにしました。

そこで、とある暑い夏の日、ミーレ表参道のショールームに見学に行ってきました。 ちなみにミーレは、幅45センチ、60センチの2サイズの食洗機を販売しています。

幅は国産と同等なのですが、高さが81センチあり、どんな大家族でもこれだけ大きければ十分すぎるでしょ、というサイズ感です。

国産食洗機の高さは40~50センチくらいなので、容量的には、1.5倍~2倍程度はあるのではないかと思います。

45センチタイプ、60センチタイプの両方を見せていただいたのですが、さすがに大きい。

製品の説明を受けながら「これだけ大きいなら45センチタイプで十分かなー」と漏らしました。

そしたら、「45センチタイプと60センチタイプ、製品価格もランニングコスト(電気代、水道代)もほとんど変わらないのでスペースがあるのであれば60センチタイプをおすすめしています」とのこと。

確かに、価格も1~2万円ほどしか違わず、加えて、45センチタイプの食洗機は、食器の洗浄完了後に前面扉を少しだけ開けて、乾燥の効率を上げるための仕組み、オートオープンという機能が搭載されていないとのことで、機能的なことも考えると、むしろ60センチタイプの方が安いくらいです。

ミーレのショールームに行った時は、1センチ足りない問題の事実を知る前だったので、とりあえず両方で検討したいので一旦下見に来てくださいとお願いしました。

2週間後、ミーレの担当者さんが下見に来られた時には、すでにビックカメラの下見が終わっていたので1センチ足りない問題は発覚しておりました。そのことをミーレ担当者さんにお話したら

「60センチタイプも設置可能ですよ!」

とのお言葉。

僕が、理解不能? 的な顔をしていると、方法を説明してくれました。

右側(コンロ側)の側板(幅2センチ)は処分して、外した左側の測板(幅1センチ)を代わりに付ける、という方法があるんだそうです。

f:id:noranuk0:20181014142929p:plain

なるほど!それなら問題なく設置できそうだし、幅60センチタイプなら隙間も空かないのでキャビネットを別途買う必要もない、価格の問題をひとまず置いておけばこれが一番理想の形。

見積価格は60センチタイプのもので製品価格、配送設置費用、配管、木工加工費込みで40万ほど。ただし、ミーレでは電気工事は請け負っていないようで、AC200Vのコンセントの設置を別途電気屋さんに依頼してくださいとのことでした。

やっぱりちょっと高いけど、でも、一人で使うには大きすぎるけど、鍋とかまな板とかなんでも入りそうだし、容量をまったく気にしなくてもよいというのは非常に魅力的です。

お値段のこともありずいぶん悩んだのですが、最終的にはミーレに決めました。

なんでも入る大きさが一番の魅力ではありましたが、国産の「なんとかイオン」的なうさん臭い宣伝文句ではなく、洗い物に特化してシンプルかつ必要十分な機能と性能が備わっていると感じたのも大きな理由です。

200Vコンセント増設の電気工事はネットで見つけた業者さんに別途手配しました。ブレーカーからキッチンまで200Vの電源を引き込むためにかかった費用はアース設置込みで約2万円くらい。

かかった費用は合計で42万円(+税)程となりました。

結構なお金はかかってしまいましたが、洗い物をしなくていいって素晴らしいと思います。

使ってみて

使用感

まだ数回しか運転していませんがとても便利です。

食器、鍋だけではなく、電子レンジの受け皿や換気扇カバー、コンロについている魚焼きグリルも洗ってみましたが、油汚れ、デンプン汚れ、ともにしっかりと洗い流すことが出来ています。

ただし、長年の間にこびりついてしまった焦げは流石に落ちなかったです。

ちなみに、最初の運転で、今まで殆ど洗ってこなかった大きなものはあらかた洗ってしまったので、ここ何回かは、割とスカスカの状態で動かしています。

ですが、大き目の鍋やフライパンも余裕をもって入れられるので、配置をあれこれ考える必要がないのはとても楽でよいです。

f:id:noranuk0:20181014145744j:plain

f:id:noranuk0:20190605151342j:plain

食洗機のメンテナンス

食洗機のメンテナンスについても手間はほとんどかかりません。

ショールームに伺ったときに話は聞いていたのですが、食洗機の底部分にゴミ受けトレイがあるので、その中身を定期的に捨てて軽く水洗いするのが基本だそうです。

流しのゴミ受けを定期的に捨てるのと同じ感覚ですね。庫内が広く手を入れるのが大変という事もないので、面倒くささは全くないです。

f:id:noranuk0:20190605151438j:plain

また、庫内はアルカリ洗剤で常に洗浄されている感じになるので、汚れることも滅多にないとは思います。とのお言葉もいただいています。

もし汚れが気になるようでしたら、メンテナンス用の洗剤も売っていますので、数か月に1回くらいそれを入れて運転してください。とも教えていただきました。

運転を開始して1年が経過したころ、1度使ってみたのですが、使用前と使用後で、特に違いがない気がしました。

洗えないもの

大きさ的に洗えないもの、というのは正直心当たりがまったくありません。木製の箸や食器も持っていないのでこちらも無問題です。 お椀だけは、一応食洗器対応のものを買いなおしました。

テフロン加工、フッ素コーティングされた鍋やフライパンなどはコーティングが劣化してくるのが早まる可能性がある、とのことですが、どうせ使い捨てなので気にせず洗っています。

竹製のさい箸も洗っていますが、劣化する気配は特にありません。

アルミ製の食器や鍋は、アルカリの作用で表面が白くなってしまいますが無害ですとのことでした。アルミ鍋はもっていましたが気にせず洗いました。確かに白くなりました。

ただし、金の塗装がされたお皿などは、洗剤の成分により、メッキ部分が黒くなってしまうとのこと。

「しらたまこ」という同人サークルさんで購入した、ご注文はウサギですかのチノちゃんのお皿が、ものすごく該当しそうなのですが・・・

なるほど、これだけは洗えないか。 f:id:noranuk0:20181014150803j:plain

食洗機用の洗剤の話

食洗機に普通の台所用の中性洗剤を使ってはいけないというのはかなり有名な話みたいです。

噂によると、故障してしまうこともあるようで、怖い怖い。

設置工事に来た人に聞いてみたところ、洗剤は、ミーレからも専用品を販売しているけど、市販品を使っていただいても構わない(ただし、食洗機専用の洗剤を使ってね)とのことでした。

市販品だと、ミーレが推奨しているのは「フィニッシュ」というメーカーの商品みたいです。

食洗機 乾燥仕上剤 フィニッシュ リンス 250ml×2

食洗機 乾燥仕上剤 フィニッシュ リンス 250ml×2

  • 発売日: 2015/08/25
  • メディア: ヘルスケア&ケア用品

ミーレから販売されている製品はタブレット洗剤60個で1500円(2018年10月現在)なので、洗剤などの費用は節約したいという方は、お値段などを比較したうえで、こういった市販品も含めてご検討されるのがよいかと思います。

高価な製品でしたし、製品検討から設置までには2か月以上かかりましたが、よいものを買えたと思っております。

ちなみに、ミーレの食洗器、現在は楽天市場からも購入することができるようになっているようです。

ミーレは基本的に値引き販売はしていないため、ミーレのショールームや公式サイトなどから購入すると定価通りの価格になります。

楽天市場で購入した場合もそれは変わらないのですが、楽天市場で購入した場合は、購入金額に応じた楽天ポイントをもらうことができます。 楽天のポイント還元率はかなり高く、お買い物マラソンなどの期間限定イベントや、SPUと呼ばれているポイントアッププログラムを併用すれば、購入価格の15%程度の楽天ポイントを受け取ることも難しくはないと思います。

例えば購入価格が40万円であれば、6万ポイント(=6万円)をポイントとして受け取れる計算になります。

もうすぐ消費税も10%に上がり、お金のニュースに関してはろくなことがないですが、こういったものを利用して少しでも節約倹約に努めたいものです。

最後に少しだけ、「もしも」の話

もしも、パナソニックリンナイ、2択で選ぶとしたらどちらを選んだか?

もしも、ミーレさんがやってくれたようなキャビネットの簡易加工のようなことを、ビックカメラ提携の業者もやってくれた場合、もしくは同様の対応をしてくれる他の業者さんを見つけることができた場合で、パナソニックリンナイのどちらを選んでいたか、という問いかけがあった場合、結論から言うと、僕はほぼ間違いなく「リンナイ」を選択していたと思います。

一つ目の理由

購入を考えていた機種に限れば、リンナイ製の発売日は2014年、それに対してパナソニックの発売日は2009年です。

後継機を出す気がない(?)、かつ、他社からも同一規格サイズの機種が販売されていないような機種を選んでしまったら、将来、その機種の生産が終了してしまった場合、買い替えに困りそうじゃないですか。。。

2つめの理由

これはミーレのショールームを見に行ったからこそ言えるのですが、スライドオープン(引き出し式)よりも、フロントオープン(扉が手前に倒れるような構造)の方が断然使いやすいと感じたからです。

設置費用、キャビネット代等すべて込みで25万円程度でやってくれる業者さんを見つけられていたら、ミーレは選んでいなかった気がいたします。

というわけで、今回は食洗機を購入したお話でした。

この記事の内容が、食洗機欲しいなー、と思っている方にとっての、選び方や段取りなどの参考になれば幸いです。

もしご興味ありましたら、ドラム式洗濯機の話もよろしければ読んでみてください。 noranuk0.hatenablog.com

目指せ送料無料!→prime未加入でも購入可能な低価格商品の探し方

こんにちは。のらぬこです。

今回は、amazonのお話です。

この記事を開いた方のほとんどは、アマゾンをこまめに利用されている方だと思います。

僕の家にも、一か月に1回以上はamazonからのお届け物が届きます。

日用品やデジタルガジェットなど、必要なものやほしいものがある程度たまったら購入するスタンスのため、1回の買い物で大体3000円から10000円程度使っています。

ただ、どうしてもすぐほしいものがあるときなど、運送業者さんには申し訳ないと若干思いつつも、小物1つで購入ボタンをポチることもあります。

そういう時に悩みの種になるのが送料の存在です。

amazonでは、1度の注文金額が一定額に満たない場合、送料がかかってしまいます。

加算される送料は、2018年7月現在では400円。高くはないんだけど、商品価格の20%以上の送料が加算されてしまうというのは正直ちょっともったいない。

昨今の運送業界のあれこれな話を聞くと、まあしょうがないよねっていう気持ちにはなるのですが、購入金額が1800円程度の場合、送料400円を払うよりも、200円分、何か適当なものを買った方が安く済ませることが出来ますよね。

今回は、低価格で、あっても無駄にはならないものを、短時間で見つける方法を書いていきたいと思います。

あわせ買い対象商品から探す

とりあえず必要になりそうなものを手早く探すのであれば、「あわせ買い対象商品」から探すのがお薦めです。

あわせ買い対象商品とは、1回の注文金額が一定金額以上(2018年7月現在は2000円)にならないと購入できない商品のことです。当然、1つ当たりの価格は安いものが多く、プライム会員専用商品も多いのですが、100円くらいから存在しています。

探し方

下記のリンクから、あわせ買い対象商品を価格の安い順に並べた時の商品一覧を参照することができます*1

https://www.amazon.co.jp/s/ref=as_li_ss_tl?keywords=%E3%81%82%E3%82%8F%E3%81%9B%E8%B2%B7%E3%81%84%E5%AF%BE%E8%B1%A1%E5%95%86%E5%93%81&rh=i:aps,k:%E3%81%82%E3%82%8F%E3%81%9B%E8%B2%B7%E3%81%84%E5%AF%BE%E8%B1%A1%E5%95%86%E5%93%81&tag=noranuk0-22&linkId=d4f58ca3252c97202220c1eae379054e&qid=1531749384&__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&sort=price-asc-rank&linkCode=ll2www.amazon.co.jp

あと少しで送料無料、というときは、この中から購入したいものを探してみるのが一番簡単で早いと思います。

商品の傾向としては、スポンジ、洗剤、サランラップ、アルミホイルなどの台所用品、ティッシュ、トイレットペーパーなどの日用品が多いです。

この中から、もうすぐ使い切りそうなもの、多少余分にあっても邪魔にならない後で必ず使うものをカートに追加すれば、無駄遣いをすることなく、送料無料の恩恵を受けることができるんじゃないかと思います。

送料無料を目指して、あと200円だけ何か買いたかったのに、気が付いたら数千円のものをカートに追加していた(経験者)という事は、なるべくなくしていきたいですね。

ということで、今回の記事は異常となります。

この記事が、皆様のamazonお買い物ライフの一助となれば幸いです。

*1:amazonの検索の仕組みの都合なのか、あわせ買い対象商品以外の商品も結果に含まれてしまっているようです

結局どこがお薦めなの?僕も使っている1番お薦めMVNO業者さんをサクッと紹介

MVNOが安いのはわかった。

乱立気味のMVNOキャリアの中で、どれが一番お薦めなのか。

これがなかなか難しい。

MVNO おすすめ」とかで検索してみると、比較サイトがずらりと並び、月額料金の高い安い、通信速度の速い遅い等が豪快で大きな表にまとめられている。

しかし、利用料金はどれもほとんど横並び、通信速度なんて、場所や時間、曜日によっても変わるものだし、比較サイトの情報がいつもあてになるとは限らない。

さらには、いくつかの比較サイトを比べてみると、速度比較の結果がサイト間でも結果がまちまち、なんてことも。

で、結局、どれがいいのか?

こんな疑問にお答えするべく、今回は、僕が使っているMVNO業者さんの紹介です。

僕はいま、「nifMo」と契約し、7Gbの音声SIMと、同じく7GbのデータSIMの2回線 合計14Gb+おまけの1Gbを3900円で運用しています。

1Gb当たりの価格が業界最安値かどうかは分かりません。また、回線速度についても、さすがに3大(もうすぐ4社目が出てきますが)キャリアと常に互角、という事もおそらくないでしょう。

ですが、価格に関しては数あるMVNO業者の中でもかなり上位、優秀なポジションにいるのではないかと思います。 速度に関しては、他のMVNO業者さんと比較することは出来ないので相対的な比較評価は出来ないですが、遅いと感じたことは少なくともここ1、2年はありません。

データ容量を比較的多めに契約しているため、月々の支払い価格に関しては、いわゆる「格安」という感じではありませんが、1Gb当たりの価格、速度(お昼時も含め)共に、とても満足しています。

僕はお昼休みにはYoutube等のサイトで動画を見ながらダラダラするのが最近の日課なのですが、少なくともここ1年ほどはストレスを感じたことはありません。

 

なお、下記の情報は、2018年7月時点での情報となります。料金体系や提供プランは、今後変更される場合があります。

nifMo の基本プラン

nifMoの運用価格(月額)を公式サイトで調べると、以下のようになっています(2018年6月現在)

容量 価格 価格(1Gbあたり)
3Gb 900円   300円
7Gb 1600円 228円
13Gb 2800円 215円

なお、通話SIMを選択する場合は上の金額に700円が加算されます。

nifMoで複数回線を利用する場合

nifMoの場合、1つの契約IDに対して1回線しか契約ができない仕組みのため、複数回線を利用したい場合は、複数の契約IDを取得し、それぞれのIDで回線契約をする形になります(IDの取得、維持費は無料です)。

さらに、ファミリープランを利用してIDをグループ管理すると、少しだけお得に運用することが出来ます。

ファミリープランでは、1回線ごとに追加0.5Gbが無料でもらえます。一人で2台持ちの2回線契約であれば各回線0.5Gb、合計1Gbの容量が追加でもらえることになります(nifMoでは「おかわり」と呼んでいます)

ちなみに、「ファミリー」という名前ですが、一人でも大丈夫です。nifMoの場合、ファミリープランというよりは、複数回線シェアプランといった名前の方がしっくりくる気がします。僕も、2回線を一人ファミリープランで運用しております。

支払いも1つにまとめることができるので、毎月の支払いが煩雑になることもありません。

 

さて、これを加味したうえで、いくつかのパターンで、1月当たりの料金、1Gb当たりの価格を計算したのが以下の表になります。

容量 価格 価格(1Gbあたり)
3Gb + 3Gb + おかわり1Gb 1800円 257円
3Gb + 7Gb + おかわり1Gb 2500円 227円
7Gb + 7Gb + おかわり1Gb 3200円 213円
13Gb + 7Gb + おかわり1Gb 4400円 209円

通話SIMへの変更はSIM1枚当たり+700円

2回線持ちという観点で見ると、少し割高な3Gbのプランを混ぜた場合はメリットが出にくいですが、例えば7Gbの2回線では、わずかな差ではありますが、1回線のみの契約で13Gbの契約をした場合よりお得になっています。

セットで割引

さらに、nifMoでは、niftyでんき、ひかり接続サービスとのセット割引があります。

niftyでんきは、例えば関東の場合、東京電力会社と契約するよりも数百円ほど安くなるようです。さらに、セット割りという事で、電気料金からさらに月額250円が割り引かれます。ひかり接続サービスも契約した場合は、これに加えてさらに月額200円が割り引かれ、両方合わせると合計450円の割引が受けられます。

電力会社、ひかり接続サービスのプロバイダが選べる、もしくは、すでにひかり接続サービスでniftyをご利用中であれば、nifMoはとても良い選択肢になるかと思います。

 

特に大容量プランが安いDMMモバイル

価格が安いと聞いたDMMモバイルの値段も調べてみました。

全部掲載するのはめんどくさいので、容量大きめのプランを中心に幾つかピックアップしてみました。

DMMモバイルのデータプラン

容量 価格 価格(1Gbあたり)
8Gb 1980円  247円
15Gb 3280円 218
20Gb 3980円 199円

SIMカード3枚まで同価格。通話SIMに変更する場合、1枚当たり +700円が加算されます。

 

DMMモバイルは特に大容量プランが安いです。20Gbプランであれば、1Gbあたりの単価が199円まで下がります。

また、DMMモバイルでは、利用特典として利用料金の10%分のDMMポイントが毎月もらえます。DMMポイントは、DMMが提供しているゲームやデジタルコンテンツなどで使えるようです。

また、DMMひかり接続サービスとのセット割引もあります。セットで利用すると月額で500円引きとなっています。

 

DMMでんきというのもあるようですが、Webの案内を見る限り、残念ながら現在は法人向けの提供のようです。

 

個人的にはアダルト系コンテンツが強いというイメージもあるDMMですが、価格、特典などを重視するのであれば、とても良いプランを提供している業者さんだと思います。

 

 

今回は、個人的にお薦めのMVNO業者さんを2社ほど紹介させていただきました。

 

今回の記事が、どなたかのご参考になれば幸いです。

 

お読みいただいてありがとうございました。

 

android:SAF、RuntimePermission等、年毎に複雑化するファイルアクセスAPI

どうものらぬこです。

今回は、androidアプリから端末内のファイルの扱いについての記事です。

端末内ストレージ(内臓ストレージ、外部SDカード)のファイル操作(編集したり、コピーしたり、削除したり)機能の実装方法は、androidOSのファイルアクセス系APIの仕組みが、OS更新ごとに仕様が複雑怪奇化、API機能の制約が増加されたなどの理由により、以前(Kitkat以前)と比べると格段に面倒くさくなっています。

今回は、その変革の軌跡をたどりながら、googleマジいい加減にしろよ●すぞ!っていう殺意にも似た感情を書いてきます。

Kitkat以前(~4.3)

アプリにPermissonさえ付与しておけば、内蔵ストレージ内のファイルもSDカード内のファイルは自由に読み書きできた時代。あの頃は良かった。

Kitkat(4.4)

一般アプリからの外部ストレージ(SDカード)への書き込みが大きく制限される /sdcard/Android/<自アプリのパッケージ名> 以外ディレクトリへの書き込みが実質不可能になる。

「実質」と書きましたが、全く不可能だったわけではないようで、実は、LOLIPOPで話題に上がったストレージアクセスフレームワーク(SAF)という仕組み、実はAPIレベル19、つまりKitkatですでに実装されていたらしいのだが、機能が中途半端なせいで外部ストレージのファイルを自由に読み書きする仕組みとしては使い物にならなかったようだ。

このバージョンから、外部SDカードの書き込み操作に限ってはAndroidManifest.xml内の Permissionの設定の効力は及ばなくなる。 たとえ記載があったとしても、アプリから上記ディレクトリ以外に書き込みを行なおうとした場合、無情にもSecurityExceptionが発生する。

なお、内蔵ストレージ内のファイル操作は、androidManifest.xml内にPermission設定をすれば従来のバージョンと同等の方法で読み書き可能。

ちなみに、システムアプリ(端末標準搭載の削除できないアプリ)からはSDカード内のファイルも自由に書き込みが可能だった。 Kitkat搭載端末には、ESファイルエクスプローラ等の優秀なファイル管理アプリよりも遥かに使いづらいアプリが標準添付されていたり。

なにとは言わないが。

この制限、root権限で /etc配下に置かれているPermission関連の設定ファイルを手動で書き換えることで、回避可能。

この回避策を実行すれば、旧バージョンと同等のことが 、何の制約もなくKitkatでも行えるようになる。

制限を回避するためにroot化した人も結構いたみたい。

まるで、セキュリティーを向上するためとかいう大義名分を嘲笑うかのよう。

昔、恒久的にroot化することなく、この制限を回避するためのツールを公開してた(消えてなければファイルも残っていると思う)。

noranuk0.hatenablog.com

かなり後発で公開したのだが、意外とダウンロード数もあり、需要はあったんでしょうね。

Lolipop(5.0)

Lolipopで新たに実装された SAF(Storage Access Framework) というAPIを利用することで、SDカード内のファイルも、ユーザが明示的に許可を出せば、自由に読み書きできるようになる。

さらに「ユーザが明示的に許可を出せば」というのがポイントで、アプリから書き込操作を行ってもよいSDカードのディレクトリを、「androidOSが用意しているディレクトリ選択画面」を使ってユーザが自分で設定しなければならない。

このandroidが用意したディレクトリ選択画面、いきなりこれを出してもエンドユーザさんは何の事かサッパリ分からないような画面のため、アプリ側で操作方法の説明を記載したり、その辺の解説サイトに説明を丸投げしたりと、色々苦労があったみたい(あった)。

エンドユーザにとっては大きな改善ではあったと思うが、新しく実装されたAPIは、従来のAPIとは全く互換性がなく、対応するにはアプリの再実装が必要で、開発側にとっては良いことばかりでもなかった。

private DocumentFile getTargetDocumentFile(String path, String treeUri) {
    String[] parts = path.replaceFirst("^/", "").split("/");
    DocumentFile target = DocumentFile.fromTreeUri(context, Uri.parse(treeUri));
    for (String part : parts) {
        target = target.findFile(part);
        if (target == null) {
            return null;
        }
    }
    return target;
}

SAFにはファイルの移動APIが存在しなかったため、ファイルの移動はコピーして元ファイルを削除という MOVEコマンドがなかったころのMS-DOSMS-DOS 3.3 みたいなことをやらないといけない。

どう考えても仕様バグみたいなこの制限は、Android7.0でようやく解消される。

// android7.0以上でのみ動作する
DocumentsContract.moveDocument(
                        contentResolver,
                        documentFile.getUri(),
                        oldPathDocument.getUri(),
                        newPathDocument.getUri());

M(6.0)

Runtime Permission といって、インストール時にアプリが使う可能性のあるすべての権限をユーザに強制承認させるのではなく、アプリインストール後、いくつかの権限については、必要になったときにユーザに承認を求めるという方式に変更される。

例えば、電話を掛ける操作や、カメラを使う操作、端末内ストレージを読み書きする操作などは、機能の利用前にユーザの明示的な承認が個別に必要となる。

これは、AndroidManifest.xmlに Permission設定を書いておくだけではだめで、権限が必要な操作の実行前に、権限を使用するためのリクエストをエンドユーザに承認してもらうためのダイアログを表示する必要があり、この部分はアプリ側で追加の実装が必要。

上でも書いたが、内蔵ストレージ・SDカード内のファイル読み書きもRuntime Permission の対象のため、ひと手間かけて、そのための処理を追加実装する必要がある。

private void requestExternalSDCardPermission() {
    if (IntentUtil.checkSelfPermission(this)) {
        new AlertDialog.Builder(this).
                setTitle(
                        getResources().getString(R.string.app_name)).
                setMessage(
                        getResources().getString(R.string.external_storage_permission_message,
                                getResources().getString(R.string.app_name))).
                setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if (shouldShowRequestPermissionRationale() ||  !Config.instance().requestSdCardPermission()) {
                            ActivityCompat.requestPermissions(LaunchActivity.this,
                                    new String[]{
                                            Manifest.permission.READ_EXTERNAL_STORAGE},
                                    REQUEST_PERMISSIONS_EDITING);
                        } else {
                            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                            Uri uri = Uri.fromParts(
                                    "package",
                                    LaunchActivity.this.getPackageName(),
                                    null); //Fragmentの場合はgetContext().getPackageName()
                            intent.setData(uri);
                            LaunchActivity.this.startActivity(intent);
                        }
                    }
                }).show();
    }
}

エンドユーザにとっては、カメラや音声の録音、通話の発信等の悪用さえるとちょっと危険な香りのする権限を、アプリごとに個別に拒否することが出来るようになるというメリットがあり、世間的には割と歓迎された。

LOLIPOPで追加されたSAFの仕様はそのまま残っており、外部ストレージへの書き込みは相変わらず SAFを使う必要がある。

LOLIPOPで実装されたSAFは本当に黒歴史だと心底思う。

N(7.0)

SAFの仕様バグ、ファイルの移動ができない不具合がようやく解消される。

ただし、android7.0が出てから2年ほど経つが、対応アプリはそんなに多くないのが実情のようで(僕が知らないだけかもしれないけど)。

そしてもう一つの大きな変更。

端末内のファイルを選択し、それを他のアプリで開くような操作に対応する場合(例えば、ファイル管理アプリで動画ファイルを選択して、それを動画再生アプリを開くときなど)、対象ファイルのパス名を指定することがこのバージョンから不可能になった。 Intentの data として、file:// スキーマを設定して、他のアプリに渡そうとすると SecurityException が発生する。

代わりに、呼び出し元アプリでContentProviderを実装して、そいつのスキーマを使えという事になっている。

エンドユーザにとってはメリットなど一つもない、場合によってはデメリットしかない気がするのだけど、なんでこんなことしたのか理解不能

デメリットとしては、例えば以下のようなことが考えられる。

ContentProviderで指定するパス名は呼び出し元アプリが自由に決められるようになっていて、ファイルシステム上同一のファイルに、毎回別のパスを割り当てることも、逆にファイルシステム上は別のファイルに、同一のパスを割り当てることも可能になっている。

したがって、呼び出し元アプリの実装方法にもよるが、例えば、アプリから動画ファイルを開く場合、動画アプリ側のレジューム再生機能などに支障をきたす場合もある。

アプリ独自にContentProvider実装しなくても、今のところはcontent:// スキーマが利用可能なのが唯一の救い。

MediaScannerConnection.scanFile(LaunchActivity.this,
        new String[]{uri.substring("file://".length())}, null,
        new MediaScannerConnection.OnScanCompletedListener() {
            @Override
            public void onScanCompleted(String path, Uri uri) {
                if (uri == null) {
                    uri = Uri.fromFile(new File(path));
                }
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setData(uri);
                context.startActivity(intent);
            }
        });

今回の話はここでおしまいだが、android 8.0がリリースされていて、その次は android 9.0 とかが待ち構えている。

最近はandroidの最新情報を追いかけていないので、8.0でまた仕様が変わったとか9.0でさらに制約が増えるとかいうことがあるのかないのかとかは分からない。

が、これ以上中途半端な仕様・制約の追加変更はやらんでいただきたいとは切に願う。

最後にひとつ。記事内に埋め込まれたコードは、過去実装したアプリコードの一部をそのまま貼り付けているため、掲載したコード単独では不完全な部分が多くあり、そのままではおそらく動作しません。

参考にされる場合は、不足していると思われる部分を各自補ってください。

というわけで、今回の記事は以上となります。

お読みいただいてありがとうございました。

【Android】Buttonに対して標準よりも小さいPadding値をJavaコードから設定する。

どうものらぬこです。

バージョンアップ開発中の個人アプリで、複数選択可能な「タグ」のような、見た目、操作性のものを作ろうとしています。

ベースコンポーネントはToggleButtonを使い、ただ、標準のものだと見た目がとてもダサいので、背景を「タグ」風の見た目にして、もう二回りPaddingを小さくしたものを作ることにしました。

ToggleButtonのbackgroundのカスタマイズは xml形式のdrawable resourceを用意してあげれば比較的簡単にできます。ボタンの状態毎にテキスト色をカスタマイズするのはこれに比べると少し面倒くさいですが、layoutでもJavaコードでも素直な実装で実現できます。

ただ、Paddingの値を小さくする方法がややトリッキーでした。 layoutで静的に用意する場合は、ややトリッキーなことをやるだけで実現できるのですが、Javaコードでボタンを動的に生成するようなコードを書く場合、Googleがますます嫌いになるようなコードを書かねばなりません。

今回作ったものは下図のようなものです。 f:id:noranuk0:20180603134701p:plain

なお、今回はToggleButtonで実装していますが、通常のボタン(Button) でも同等の実装で実現できるかと思います。

layout.xmlで静的なボタンとして実装する場合

まずは、ボタン背景をカスタマイズするために背景の drawable.xml と、ボタンの状態によってテキスト色を変化させるための textcolorselector.xml を用意します。

まずは、背景色用のxmlです。ボタンの状態によって見た目を変えたいため、selectorを使って状態ごとのフィルターを作成しています。これを、drawable/background_tagbotton.xml 等の名前で保存してください。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true"
        android:state_enabled="true">
        <shape android:shape="rectangle">
            <corners
                android:radius="5dp" />
            <solid
                android:color="@color/colorAccentAlpha"/>
            <stroke
                android:width="1dp"
                android:color="@color/colorAccent"/>
        </shape>
    </item>

    <item android:state_checked="false"
        android:state_enabled="true">
        <shape android:shape="rectangle">
            <corners
                android:radius="5dp" />
            <stroke
                android:width="1dp"
                android:color="@color/colorAccentAlpha"/>
        </shape>
    </item>

    <item android:state_checked="true"
        android:state_enabled="false">
        <shape android:shape="rectangle">
            <corners
                android:radius="5dp" />
            <solid
                android:color="@color/colorAccentAlpha"/>
        </shape>
    </item>

    <item android:state_checked="false"
        android:state_enabled="false">
        <shape android:shape="rectangle">
            <corners
                android:radius="5dp" />
        </shape>
    </item>
</selector>

次に、テキスト色用の drawable xmlリソースです。背景と同様に、ボタンの状態によって見た目を変えたいため、selectorを使って状態ごとのフィルターを作成しています。これを、drawable/textcolor_tagbotton.xml 等の名前で保存してください。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true" android:color="@color/colorAccent"/>
    <item android:state_checked="false" android:color="@color/colorAccentAlpha"/>
</selector>

最後に、layout.xml で ToggleButton を作成します。Paddingの指定もここで行います。

<ToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:minHeight="0dp"
        android:minWidth="0dp"
        android:padding="4dp"
        android:textOn="on"
        android:textOff="off"
        android:textStyle="normal"
        android:background="@drawable/background_tagbutton"
        android:textColor="@drawable/textcolor_tagbutton"
        android:layout_marginTop="4dp"
        android:layout_marginBottom="4dp"
        android:layout_marginStart="2dp"
        android:layout_marginEnd="2dp"
        android:textAllCaps="false"
        android:text="sample text"/>

padding の指定を書いただけでは、小さなボタンは作れません。

        android:minHeight="0dp"
        android:minWidth="0dp"

の2つの設定が必要です。

java コードで動的なボタンとして実装する場合。

javaコードで実装する場合も、大抵の場合は、コントロールのオブジェクトをnewした後に、プロパティーを設定する要領で、javaのメソッド呼び出しで設定してあげるだけです。

dataBinding.detailContainer.removeAllViews();
float scale = getResources().getDisplayMetrics().density;

    ToggleButton button = new ToggleButton(this);
    button.setText("");
    button.setTextOn("on);
    button.setTextOff("off");

    button.setBackgroundResource(R.drawable.background_tagbutton;
    button.setAllCaps(false);
    try {
        @SuppressLint("ResourceType") XmlResourceParser parser = getResources().getXml(R.drawable.textcolor_tagbutton);
        ColorStateList colors = ColorStateList.createFromXml(getResources(), parser);
        button.setTextColor(colors);
    } catch (Exception e) {
        // handle exceptions
    }

    button.setPadding((int)(4 * scale + 0.5f), (int)(4 * scale + 0.5f), (int)(4 * scale + 0.5f), (int)(4 * scale + 0.5f));
    button.setMinHeight(0);
    button.setMinimumHeight(0);
    button.setMinWidth(0);
    button.setMinimumWidth(0);

    dataBinding.detailContainer.addView(button);

paddingに標準より小さい値を設定したボタンをjavaコードで生成する場合も基本的には一緒です。

ただし、最小幅、最小高を設定する部分は、setPadding / setMinHeight / setMinWidth の呼び出しだけでは不十分です。

上のコードの通り、幅と高さそれぞれについて

    button.setMinWidth(0);
    button.setMinimumWidth(0);
    button.setMinHeight(0);
    button.setMinimumHeight(0);

の、2つのメソッドの呼び出しが必要です。

getMinHeight / getMinimuHeight、getMinWidth / getMinimumWidth の違いは?

ToggleButton  |  Android Developers のあたりを漁ってみたのですが、情報はなく、正直よくわからん。

IDEのコード補完機能って便利ですねー

というわけで、未解決の伏線を残したまま終了、なかんじではございますが、今回の記事は以上となります。

お読みいただいてありがとうございました。

BIGENTERBK

BIGENTERBK

こちらもどうぞ

noranuk0.hatenablog.com