[Android]Quick Return UIを実装してみる(WebView編)
QuickReturnの続きです。前回はこちらんでWebViewの時どうやるのって話。クロムとかくろむとかやってますね。ちなみにWebViewの時も簡単にできるかというと面倒です。1.ヘッダー問題。こちらはApi 18までは非公開Apiでできます。Api16以下はsetEmbeddedTitleBarをリフレクション Method m = getClass().getMethod("setEmbeddedTitleBar", View.class); m.invoke(this, v);Api16-18はandroid.webkit.WebViewClassic.TitleBarDelegateなクラス、メソッド用意してカスタムなWebViewにTitleBarDelegateをimplementsして@Overridepublic void onSetEmbeddedTitleBar(View title) {}を入れてやればいい。だけどまぁApi19では完全に死んでます。とりあえずうちのNexsusでは出ません。あれですかねchromium化すると同時に完全になくしたんですかね?でも自分たちは影響ないように使ってるんですかね?独自で実装してそうですが。。色々開発者フォーラムあさったら自分で実装するのは私たちは気にしない的な回答を見ましたよ。うん、なんかいい方法あれば教えてください。というわけで上記の方法はいまんとこ使えなくなるのでここでは特に書きません。TitleBarWebViewという素晴らしい対応クラスがあるのでそちらを検索すると色々わかります。*サンプルにも入れてますが。と長々かきましたが、ようは自前で用意しろってことっぽい。WebView自体がオワコンなのかはどうかはあまり使わないクラスなのでわかりませんが先に上げたTitleBarWebViewを参考にしながら改造してみる。調べてみるとabsoluteなViewGroupらしいのでヘッダーをaddViewして位置をずらせばよさそうです。WebViewをextendedしたクラスを用意して。------------------------------ private View mTitle; private int titleHeight;//タイトルバーセット public void setEmbeddedTitleBar(View v) { if (this.mTitle == null) { this.mTitle = v; addView(mTitle, 0); } } public View getEmbeddedTitleBar() { return mTitle; }//タイトルバー削除 public void removeEmbeddedTitleBar() { if (this.mTitle != null) { removeView(mTitle);// (mTitle); invalidate(); mTitle = null; } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); titleHeight = mTitle == null ? 0 : mTitle.getMeasuredHeight(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return true; } private boolean touchInTitleBar; @Override public boolean dispatchTouchEvent(MotionEvent me) { boolean wasInTitle = false; switch (me.getActionMasked()) { case MotionEvent.ACTION_DOWN: touchInTitleBar = (me.getY() <= visibleTitleHeight()); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: wasInTitle = touchInTitleBar; touchInTitleBar = false; break; } if (touchInTitleBar || wasInTitle) { View title = getChildAt(0); if (title != null) { // this touch belongs to title bar, dispatch it here me.offsetLocation(0, getScrollY()); return title.dispatchTouchEvent(me); } } me.offsetLocation(0, -titleHeight); return super.dispatchTouchEvent(me); } /** * @return visible height of title (may return negative values) */ private int visibleTitleHeight() { return titleHeight - getScrollY(); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (mTitle != null) mTitle.offsetLeftAndRight(l - mTitle.getLeft()); } private Rect mClipBounds = new Rect(); @Override protected void onDraw(Canvas c) { c.save(); if (mTitle != null) { final int sy = getScrollY(); final int sx = getScrollX(); int titleBarOffs = visibleTitleHeight(); mClipBounds.left = sx; mClipBounds.top = sy; mClipBounds.right = mClipBounds.left + getWidth(); mClipBounds.bottom = mClipBounds.top + getHeight(); c.clipRect(mClipBounds); if (titleBarOffs < 0) titleBarOffs = 0; c.translate(0,titleBarOffs); } super.onDraw(c); c.restore(); }-----------------------------という具合で中途半端だけどなんとかでけた。。スクロールしたときに遅れてタイトルが動くんですよね。。。気になる。。。だけど今回ヘッダーはあくまでQuickReturnで余白として使いたいだけなのでいったん無視しませう。。さて次です。2.スクロール問題。ようはWebViewのスクロール情報をどう取るかという話ですが、WebViewにはOnScrollListener的なもんがない。OnTouchListenerでも取れるんですがなんとなく面倒。何が面倒っていうとWeb内のインプット系のアクションとかが起こったときにたまに位置がチェンジされたりするんですがその際のスクロール情報が取れない。というかイベントが来ない。。。取得方法もあるかと思いますがね。。なのでWebViewでもScroll系のコールバックを呼べるようにします。WebViewをextendedしたクラスを用意して。------------------------------ private OnScrollChangedCallback mOnScrollChangedCallback; @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (mOnScrollChangedCallback != null) mOnScrollChangedCallback.onScroll(l, t); } public OnScrollChangedCallback getOnScrollChangedCallback() { return mOnScrollChangedCallback; } public void setOnScrollChangedCallback( final OnScrollChangedCallback onScrollChangedCallback) { mOnScrollChangedCallback = onScrollChangedCallback; } public static interface OnScrollChangedCallback { public void onScroll(int l, int t); }------------------------------これでよいです。あとは1と2を合体します。かぶるのはonScrollChangedのみなのでそこはこんな感じ。------------------------------ @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (mTitle != null) mTitle.offsetLeftAndRight(l - mTitle.getLeft()); if (mOnScrollChangedCallback != null) mOnScrollChangedCallback.onScroll(l, t); }------------------------------これであとはListViewのときと同じようできます。注意点としてWebViewのタイトルに入れるViewは入れる前にsetLayoutParamsをしないとちゃんとレイアウトが効かないっぽい。。。んで、ここまで書いたが結構ごまごまするのでサンプルプロジェクトを用意してますん。プロジェクト>WebViewQuickReturnActivityhttps://drive.google.com/file/d/0B_niJgzazrXxbFRyRnRZMHRkWmM/edit?usp=sharing