キーボード出現時にキャレットが隠れる
公開から連日アップデートしてるブログエディターだが、
今回は、ソフトウェアキーボード出現時に、キャレットが下の方にあるとキーボードで隠れちゃう。
改善したい・・・
というわけなんだが、
android.view.ViewにonSizeChangedがあって、Viewのリサイズ時に呼び出される。
が、イベントリスナの登録はできないんで、カスタムViewを作ってイベントリスナを登録できるようにしてみた。
今回問題のViewはWebViewなんで、カスタムWebView。
CustomWebView.java
MainActivity.java
てな感じで、Viewのリサイズ時にMainActivity側で処理することができた。
layoutの.xmlファイルでカスタムViewを配置する場合は、(Context context,AttributeSet attrs)のコンストラクタが使われるみたいなんでOverride。
で、.xmlファイルには、<パッケージ名.クラス名>でカスタムViewが設置できる。
javaファイルで設置するなら、ほとんどの場合(Context context)で設置するから、そっちのコンストラクタをOverrideだね。
MainActivity側で処理できるように、イベントリスナのinterfaceを定義して、リスナ登録用のメソッドを用意。
onSizeChangedに追加でリスナを実行するようにする感じだね。
で、今回はWebViewのcontenteditable要素への入力でソフトキーボードが出現する時に問題が生じるんだが、
元々「改行→<br>」変換処理で要素が拡大してViewからはみ出した場合にスクロールする処理を入れてあるんだが、
その処理はrangeに一時的に<span>を入れて、<span>の座標がはみ出した場合にスクロールするようにしてある。
同じようにやろうとしたんだが、改行時処理と違って文字入力時処理だと、処理によってキーボードが消えちゃうって問題が発生した。
文字入力中にjavascriptでrangeに変更加えるのは問題生じそうな気もするし、javascript側で処理するのはやめたほうが良さそう・・・
Java側での処理を考えて、onSizeChangeddから元のサイズと新しいサイズが取得できるから、差をスクロールさせればできるとも思ったんだが、
View中のキャレット位置が上の方にあるって場合も考えられるし、その場合にスクロールさせちゃうと逆に消えちゃうね・・・
Java側でキャレット座標の取得ができないか調べたが、どうもできなそう。
android.view.ViewにあるgetBaseline()が怪しいかとも思ったが、WebViewでは常に-1ぽい・・・
AndroidManifest.xmlで「android:windowSoftInputMode="adjustResize"」を設定するとソフトウェアキーボード出現時にアクティビティが伸縮するらしいんだが、
うちの場合layoutで対応できてるのか、そもそもこれ設定しなくても伸縮してる。
問題はActivityのサイズじゃなくてView内のスクロール量だから、これは関係無さそう。
お手上げぽいんで、この問題は放置することにした。
EditTextでキーボード出現した場合どうなるのか試したが、EditTextの場合、何もせずに良い動きしてくれる。
WebViewの方の挙動を再度よく確認してみたが、キーボード出現時自体は自動で位置調整してくれるんだが、
1文字入力して変換候補がでた時に位置調整してくれない。EditTextなら問題ない。
WebViewでも、1文字入力で変換候補が出てキャレットが隠れるが、そのまま2文字目を入力すると再度位置調整してくれて画面内にキャレットが入る。
変換候補出現時の処理にWebViewはバグがあるっぽいな。
キャレットの座標が取得できないと位置調整できないと思うが、WebViewでもキーボード出現時と2文字目入力時は位置調整してくれるってことは、どこかで座標取得できそうな気はするが・・・
今回は、ソフトウェアキーボード出現時に、キャレットが下の方にあるとキーボードで隠れちゃう。
改善したい・・・
というわけなんだが、
android.view.ViewにonSizeChangedがあって、Viewのリサイズ時に呼び出される。
が、イベントリスナの登録はできないんで、カスタムViewを作ってイベントリスナを登録できるようにしてみた。
今回問題のViewはWebViewなんで、カスタムWebView。
CustomWebView.java
import android.webkit.WebView;
import android.content.Context;
import android.util.AttributeSet;
public class CustomWebView extends WebView{
public CustomWebView(Context context,AttributeSet attrs){
super(context,attrs);
}
public interface customOnSizeChangedListener{
public void customOnSizeChanged(int w,int h,int oldw,int oldh);
}
private customOnSizeChangedListener listener;
public void customSetOnSizeChangedListener(customOnSizeChangedListener listener){
this.listener=listener;
}
protected void onSizeChanged(int w,int h,int oldw,int oldh){
super.onSizeChanged(w,h,oldw,oldh);
listener.customOnSizeChanged(w,h,oldw,oldh);
}
}
import android.content.Context;
import android.util.AttributeSet;
public class CustomWebView extends WebView{
public CustomWebView(Context context,AttributeSet attrs){
super(context,attrs);
}
public interface customOnSizeChangedListener{
public void customOnSizeChanged(int w,int h,int oldw,int oldh);
}
private customOnSizeChangedListener listener;
public void customSetOnSizeChangedListener(customOnSizeChangedListener listener){
this.listener=listener;
}
protected void onSizeChanged(int w,int h,int oldw,int oldh){
super.onSizeChanged(w,h,oldw,oldh);
listener.customOnSizeChanged(w,h,oldw,oldh);
}
}
MainActivity.java
((CustomWebView)view).customSetOnSizeChangedListener(new CustomWebView.customOnSizeChangedListener(){
public void customOnSizeChanged(int w,int h,int oldw,int oldh){
処理
}
});
public void customOnSizeChanged(int w,int h,int oldw,int oldh){
処理
}
});
てな感じで、Viewのリサイズ時にMainActivity側で処理することができた。
layoutの.xmlファイルでカスタムViewを配置する場合は、(Context context,AttributeSet attrs)のコンストラクタが使われるみたいなんでOverride。
で、.xmlファイルには、<パッケージ名.クラス名>でカスタムViewが設置できる。
javaファイルで設置するなら、ほとんどの場合(Context context)で設置するから、そっちのコンストラクタをOverrideだね。
MainActivity側で処理できるように、イベントリスナのinterfaceを定義して、リスナ登録用のメソッドを用意。
onSizeChangedに追加でリスナを実行するようにする感じだね。
で、今回はWebViewのcontenteditable要素への入力でソフトキーボードが出現する時に問題が生じるんだが、
元々「改行→<br>」変換処理で要素が拡大してViewからはみ出した場合にスクロールする処理を入れてあるんだが、
その処理はrangeに一時的に<span>を入れて、<span>の座標がはみ出した場合にスクロールするようにしてある。
同じようにやろうとしたんだが、改行時処理と違って文字入力時処理だと、処理によってキーボードが消えちゃうって問題が発生した。
文字入力中にjavascriptでrangeに変更加えるのは問題生じそうな気もするし、javascript側で処理するのはやめたほうが良さそう・・・
Java側での処理を考えて、onSizeChangeddから元のサイズと新しいサイズが取得できるから、差をスクロールさせればできるとも思ったんだが、
View中のキャレット位置が上の方にあるって場合も考えられるし、その場合にスクロールさせちゃうと逆に消えちゃうね・・・
Java側でキャレット座標の取得ができないか調べたが、どうもできなそう。
android.view.ViewにあるgetBaseline()が怪しいかとも思ったが、WebViewでは常に-1ぽい・・・
AndroidManifest.xmlで「android:windowSoftInputMode="adjustResize"」を設定するとソフトウェアキーボード出現時にアクティビティが伸縮するらしいんだが、
うちの場合layoutで対応できてるのか、そもそもこれ設定しなくても伸縮してる。
問題はActivityのサイズじゃなくてView内のスクロール量だから、これは関係無さそう。
お手上げぽいんで、この問題は放置することにした。
EditTextでキーボード出現した場合どうなるのか試したが、EditTextの場合、何もせずに良い動きしてくれる。
WebViewの方の挙動を再度よく確認してみたが、キーボード出現時自体は自動で位置調整してくれるんだが、
1文字入力して変換候補がでた時に位置調整してくれない。EditTextなら問題ない。
WebViewでも、1文字入力で変換候補が出てキャレットが隠れるが、そのまま2文字目を入力すると再度位置調整してくれて画面内にキャレットが入る。
変換候補出現時の処理にWebViewはバグがあるっぽいな。
キャレットの座標が取得できないと位置調整できないと思うが、WebViewでもキーボード出現時と2文字目入力時は位置調整してくれるってことは、どこかで座標取得できそうな気はするが・・・