输入法是dialog,还是全屏dialog,且不会被dismiss,显示与隐藏系统调用方法为showWindow(true)和hide(),以下是输入法Window创建,SoftInputWindow继承Dialog,这个不必多说,
mWindow =?new?SoftInputWindow(this,?"InputMethod", mTheme,?null,?null, mDispatcherState,
????????????????WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM,?false);
????????mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars());
????????mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM);
????????mWindow.getWindow().getAttributes().setFitInsetsIgnoringVisibility(true);
至于全屏的依据,可以看SoftInputWindow initDockWindow方法,
看,写入了WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
这个Flag啥意思呢?就是将窗口放置在整个屏幕内,忽略父容器的限制,
private?void?initDockWindow() {
???????WindowManager.LayoutParams lp = getWindow().getAttributes();
???????lp.type = mWindowType;
???????lp.setTitle(mName);
???????lp.gravity = mGravity;
???????updateWidthHeight(lp);
???????getWindow().setAttributes(lp);
???????int?windowSetFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
???????int?windowModFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
???????????????WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
???????????????WindowManager.LayoutParams.FLAG_DIM_BEHIND;
???????if?(!mTakesFocus) {
???????????windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
???????}?else?{
???????????windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
???????????windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
???????}
???????getWindow().setFlags(windowSetFlags, windowModFlags);
???}
如果要输入法上移,必须调整dialog中的布局,
在InputMethodService方法中,initView如下,
mWindow.setContentView(mRootView),关键,
mWindow是SoftInputWindow,继承Dialog,因此这是设置视角;
如何,一些成员的初始化在此进行,如mInputFrame和mCandidatesFrame,这是啥呢?在setInputView中回调onCreateView方法,拿到三方输入法自定义的View,
所以显示在我们面前的视野就是mInputFrame;
void?initViews() {
???????mInitialized =?false;
???????mViewsCreated =?false;
???????mShowInputRequested =?false;
???????mShowInputFlags =
?0;
???????mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService);
???????mRootView = mInflater.inflate(
???????????????com.android.internal.R.layout.input_method,?null);
???????mWindow.setContentView(mRootView);
???????mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsComputer);
???????mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
???????if?(Settings.Global.getInt(getContentResolver(),
???????????????Settings.Global.FANCY_IME_ANIMATIONS,?0) !=?0) {
???????????mWindow.getWindow().setWindowAnimations(
???????????????????com.android.internal.R.style.Animation_InputMethodFancy);
???????}
???????mFullscreenArea = mRootView.findViewById(com.android.internal.R.id.fullscreenArea);
???????mExtractViewHidden =?false;
???????mExtractFrame = mRootView.findViewById(android.R.id.extractArea);
???????mExtractView =?null;
???????mExtractEditText =?null;
???????mExtractAccessories =?null;
???????mExtractAction =?null;
???????mFullscreenApplied =?false;
???????mCandidatesFrame = mRootView.findViewById(android.R.id.candidatesArea);
???????mInputFrame = mRootView.findViewById(android.R.id.inputArea);
???????mInputView =?null;
???????mIsInputViewShown =?false;
???????mExtractFrame.setVisibility(View.GONE);
???????mCandidatesVisibility = getCandidatesHiddenVisibility();
???????mCandidatesFrame.setVisibility(mCandidatesVisibility);
???????mInputFrame.setVisibility(View.GONE);
???}
因为要上移输入法,尝试对window的attribute参数下手,失败告终,因为设置y参数对全屏输入法无效,由于service的onCreate方法new SoftInputWindow时,传入Gravity和Bottom,输入法就默认显示底部?调试时改为Top,依然显示在底部,比较费解。
FullscreenArea = mRootView.findViewById(com.android.internal.R.id.fullscreenArea);具体资源看不到,这个应该覆盖了整个屏幕
综上所述,输入法类似以下布局,暂不讨论屏幕旋转之内,这个在SoftInputWindow会更新Gravity,
处理上移问题,就要上移mInputFrame,
怎么移?mInputFrame本身是Framelayout,而且位置在android资源文件中写死了,通过代码动态移动?
想过WindowManager的updateLayout,可是布局参数呢?
或者直接调用setY,可问题是这样的效果类似动画,原View并没有移动,也就导致点击事件不可用,
或者view的startMoveTask方法?感觉都不行,
一般三方自定义输入法时,需要继承InputMethodService类,这是个标准,
重写其中onCreateVIew方法,也就传入自定义输入法布局,系统通过如下方法回调,
public?void?updateInputViewShown() {
???????boolean?isShown = mShowInputRequested && onEvaluateInputViewShown();
???????if?(mIsInputViewShown != isShown && mDecorViewVisible) {
???????????mIsInputViewShown = isShown;
???????????mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
???????????if?(mInputView ==?null) {
???????????????initialize();
???????????????View v = onCreateInputView();
???????????????if?(v !=?null) {
???????????????????setInputView(v);
???????????????}
???????????}
???????}
???}
之后,通过setInputView方法设置显示在用户面前的视野,可以看到,视野添加到mInputFrame中,对于另外一个方法setCandidatesView,就是候选视图,暂不多说,候选嘛。
public?void?setInputView(View view) {
???????mInputFrame.removeAllViews();
???????mInputFrame.addView(view,?new?FrameLayout.LayoutParams(
???????????????ViewGroup.LayoutParams.MATCH_PARENT,
???????????????ViewGroup.LayoutParams.WRAP_CONTENT));
???????mInputView = view;
???}
所以我们要挪动输入法,可以在这里做文章,即添加一点参数,让mInputView上移一点,
FrameLayout.LayoutParams提供了bottomMargin参数,即让咱们的mInputView相对bottom移动一点距离,单位是像素不是dp,
|