如何解决软键盘弹出引起的各种不适

本文介绍了如何在Android应用中解决软键盘遮挡输入框的问题,通过特定的配置参数和布局技巧,确保输入框始终可见并保持良好的用户体验。

原文链接:http://unicorn25.iteye.com/blog/916504

在做登录和注册页面的时候,经常会遇到诸如软键盘挡住输入框的情况,android为此提供了一系列的的配置参数供选择,你可以在androidmanufist.xml的对应Activity的windowSoftInputMode属性中选择如下4者之一进行配置(紫色字):



       <activity android:name=".LoginAc"
 
                  android:label="@string/app_name"
                  android:windowSoftInputMode="stateHidden|adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

四个参数意思如下:

SOFT_INPUT_ADJUST_NOTHING:         不调整(输入法完全直接覆盖住,未开放此参数)

SOFT_INPUT_ADJUST_PAN:                 把整个Layout顶上去露出获得焦点的EditText,不压缩多余空间,见图1

SOFT_INPUT_ADJUST_RESIZE:            整个Layout重新编排,重新分配多余空间,见图2

SOFT_INPUT_ADJUST_UNSPECIFIED:  系统自己根据内容自行选择上两种方式的一种执行(默认配置)


这里的多余空间指的是控件们通过weight分配机制得到的额外空间。


图1


图2


图3

代码实现方式为:
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

但是,这样的配置方法一般都很难完全满足需要,有得应用会做得比较好,让顶上去的Layout能够通过scrollbar滚动。这种解决方法网上有各种介绍,本人也是第一时间从网上找解决方法参考,但最终发现都并未把原理说清,而且大多数有错误,或者有多余配置,于是,我从android系统中源码中找参考案例,在Email应用中,找到了我想要的。效果如图4,5。


图4


图5

其对应的Activity是AccountSetupBasics.java,对应的xml文件为account_setup_basics.xml。

来学习下它的xml写法


<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:fillViewport="true"
    android:scrollbarStyle="outsideInset" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical" >
            <TextView
                android:id="@+id/instructions"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dip"
                android:textSize="20sp"
                android:text="@string/accounts_welcome"
                android:textColor="?android:attr/textColorPrimary" />
            <View
                android:layout_width="fill_parent"
                android:layout_height="0dip"
                android:layout_weight="1" />
            <EditText
                android:id="@+id/account_email"
                android:hint="@string/account_setup_basics_email_hint"
                android:inputType="textEmailAddress"
                android:imeOptions="actionNext"
                android:layout_height="wrap_content"
                android:layout_width="fill_parent" />
            <EditText
                android:id="@+id/account_password"
                android:hint="@string/account_setup_basics_password_hint"
                android:inputType="textPassword"
                android:imeOptions="actionDone"
                android:layout_height="wrap_content"
                android:layout_width="fill_parent"
                android:nextFocusDown="@+id/next" />
            <CheckBox
                android:id="@+id/account_default"
                android:layout_height="wrap_content"
                android:layout_width="fill_parent"
                android:text="@string/account_setup_basics_default_label"
                android:visibility="gone" />
            <View
                android:layout_width="fill_parent"
                android:layout_height="0dip"
                android:layout_weight="1" />
        </LinearLayout>

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="54dip"
            android:background="@android:drawable/bottom_bar" >
            <Button
                android:id="@+id/manual_setup"
                android:text="@string/account_setup_basics_manual_setup_action"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:minWidth="@dimen/button_minWidth"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true" />
            <Button
                android:id="@+id/next"
                android:text="@string/next_action"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:minWidth="@dimen/button_minWidth"
                android:drawableRight="@drawable/button_indicator_next"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true" />
        </RelativeLayout>
    </LinearLayout>
</ScrollView>

1  它完全把ScrollView作为了一个根Layout,而不是网上好多文章写的在一个Linearlayout里面嵌入一个ScrollView(貌似这种是行不通的)。

然后把我们原来的根Layout搬入ScrollView(ScrollView只能有一个子控件),我查了下androidmanifist.xml和代码,未做任何以上2种方法的配置。

2  它定义了2个0dip的View帮助分配空间(设置其weight吃掉剩余空间,保证输入框处于界面中心位置),可以猜测出这里系统调用的是SOFT_INPUT_ADJUST_RESIZE参数,当所有有实际内容的控件空间总和超出特定范围时,ScrollView开始发挥作用。

 

如此,完美的解决我们遇到的问题。

另外,网上有人说想用SOFT_INPUT_ADJUST_RESIZE ,但又不希望背景图片被压缩,只要按如上方法把Linearlayout的背景图片设置好即可。



package com.boncfc.mgrapp.fhVideo.teller; import android.app.Activity; import android.app.Notification; import android.app.ProgressDialog; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.RelativeLayout; import androidx.appcompat.app.AppCompatActivity; import com.boncfc.mgrapp.R; import com.fhuvideo.FHLiveMacro; import com.fhuvideo.FHLiveSessionParams; import com.fhuvideo.FHParams; import com.fhuvideo.adviser.FHTellerParams; import com.fhuvideo.adviser.tool.FHAPlayer; import com.fhuvideo.bank.FHPermission; import com.fhuvideo.bean.FHLog; import com.fhvideo.bankui.FHLivelisenter; import com.fhvideo.bankui.FHVideoManager; import com.fhvideo.bankui.bean.FHUIEvent; import com.fhvideo.bankui.call.FHCallActivity; import com.fhvideo.bankui.live.FHLiveActivity; import com.fhvideo.bankui.util.ToastUtil; import com.fhvideo.fhcommon.FHBusiCallBack; public class MainFhActivity extends AppCompatActivity { private static final String TAG = "MainFhActivity"; private Activity activity; private boolean isMetting = false; private ProgressDialog pd; private RelativeLayout outViewGroup; private WebView outWebView; private Handler mHandler = new Handler(); // 状态跟踪变量(新增) public static boolean isLiveActive = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 修改点1:设置透明背景避免白屏 getWindow().setBackgroundDrawable(null); setContentView(new View(this)); getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); activity = this; FHLiveSessionParams.setImChannelType(FHTellerParams.TX); setNoti(); initPD(); FHPermission.getInstance().checkPermission(activity); login(); } private void setNoti() { NotifyObject notifyObject = new NotifyObject(); notifyObject.content = "投屏内容"; notifyObject.title = "投屏标题"; notifyObject.subText = ""; notifyObject.param = ""; Notification notification = NotificationUtil.createScreenNotification(getApplicationContext(), notifyObject); //设置投屏通知 FHVideoManager.getInstance().setScreenNotification(notification); NotifyObject LivennotifyObject = new NotifyObject(); LivennotifyObject.content = "会话内容"; LivennotifyObject.title = "会话标题"; LivennotifyObject.subText = ""; LivennotifyObject.param = ""; Notification Livenotification = NotificationUtil.createScreenNotification(getApplicationContext(), LivennotifyObject); FHVideoManager.getInstance().setLiveForegroundNotification(Livenotification); } private void initPD() { pd = new ProgressDialog(activity); pd.setMessage("加载中..."); pd.setCanceledOnTouchOutside(false); } private void showPd() { if (!pd.isShowing()) { pd.show(); } } private void cancelPd() { if (pd.isShowing()) pd.cancel(); } private void login() { if (!FHTellerParams.isConnected()) { ToastUtil.getInatance(activity).show(getString(R.string.fh_not_net)); return; } String uid = getIntent().getStringExtra("tellerUid"); String pwd = getIntent().getStringExtra("password"); String dept = "0_2024"; String authNumber = getIntent().getStringExtra("authNumber"); if (TextUtils.isEmpty(uid) || TextUtils.isEmpty(pwd)) { ToastUtil.getInatance(activity).show("请输入视频柜员工号和密码!"); return; } showPd(); FHVideoManager.getInstance().loginAutoCreate(uid, pwd, dept, authNumber, new FHBusiCallBack() { @Override public void onSuccess(String s) { Log.i(TAG, "登录成功"); cancelPd(); startLiveActivity(); } @Override public void onError(String s) { Log.e(TAG, "登录失败: " + s); cancelPd(); if (!TextUtils.isEmpty(s) && (s.contains("40100") || s.contains("40024"))) { FHVideoManager.getInstance().forceFinishLastSession(FHParams.getUid(), null); } ToastUtil.getInatance(activity).show(s); finish(); } }); } private void startLiveActivity() { if (FHCallActivity.isStart) return; // 修改点3:明确状态标记 isLiveActive = true; isMetting = true; Log.d(TAG, "启动视频页面"); FHLiveActivity.setLiveLisenter(new FHLivelisenter() { @Override public void onVideoEvent(String type, String msg) { switch (type) { case FHTellerParams.FH_ON_START: configOutViewGroup(); Log.d(TAG, "会话开始"); break; case FHTellerParams.FH_VIDEO_END: case FHTellerParams.FH_ON_QUIT: finishCallMeeting(msg); break; case FHTellerParams.FH_ON_LEAVE: minimizeAppSafely(); break; case FHUIEvent.ONCLICK_FLOAT: handleFloatClick(); break; } } }); Intent intent = new Intent(activity, FHLiveActivity.class); startActivity(intent); // 修改点4:禁用跳转动画 overridePendingTransition(0, 0); } // 修改点5:新增安全最小化方法 private void minimizeAppSafely() { Log.d(TAG, "执行安全最小化"); moveTaskToBack(true); mHandler.postDelayed(() -> isLiveActive = false, 1000); } // 修改点6:优化小窗点击处理 private void handleFloatClick() { Log.d(TAG, "处理小窗点击"); mHandler.postDelayed(() -> { if (isMetting) { Intent intent = new Intent(activity, FHLiveActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); startActivity(intent); overridePendingTransition(0, 0); } }, 200); } // 保留原有方法(未修改) private void configOutViewGroup() { if (outViewGroup == null) { outViewGroup = new RelativeLayout(getApplicationContext()); outViewGroup.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT )); } if (outWebView == null) { outWebView = new WebView(outViewGroup.getContext()); WebSettings webSettings = outWebView.getSettings(); webSettings.setJavaScriptEnabled(true); outWebView.setWebViewClient(new WebViewClient()); outWebView.loadUrl(""); // 配置业务URL } outViewGroup.removeAllViews(); outViewGroup.addView(outWebView); FHVideoManager.getInstance().configOutViewGroup(outViewGroup); } // 保留原有方法(未修改) private void destroyOutViewGroup() { if (outWebView != null) { outWebView.stopLoading(); outWebView.removeAllViews(); outWebView.destroy(); outWebView = null; } if (outViewGroup != null) { outViewGroup.removeAllViews(); } } private void finishCallMeeting(String msg) { Log.d(TAG, "结束会话: " + msg); isMetting = false; isLiveActive = false; destroyOutViewGroup(); } @Override protected void onResume() { super.onResume(); Log.d(TAG, "onResume"); mHandler.removeCallbacksAndMessages(null); } @Override protected void onRestart() { super.onRestart(); Log.d(TAG, "onRestart isMetting=" + isMetting); // 修改点7:优化返回处理 mHandler.postDelayed(() -> { if (isMetting && !isLiveActive) { Log.d(TAG, "恢复视频页面"); Intent intent = new Intent(activity, FHLiveActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); startActivity(intent); overridePendingTransition(0, 0); } }, 300); } @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy"); // 修改点8:确保资源释放 mHandler.removeCallbacksAndMessages(null); FHAPlayer.getInstance().stopPlayer(); destroyOutViewGroup(); } }这个写的java中,这是一个视频功能调用sdk,启动视频各种功能,但是现在首次点击最小化,会有一个白屏/黑屏,再点返回才能到app(混合开发的vue页面),后续的最小化都没有问题,根据上面的代码,分析什么原因导致的,并给出解决的办法,修改什么地方才能解决
最新发布
08-02
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值