Android 处理软键盘遮挡问题
需要达到的效果:
方式一:使用scrollTo
当软键盘弹起时,通过scrollTo滚动出被遮挡的地方。
监听软键盘状态工具类
public class SoftKeyboardListener {
private static int lastVisibleHeight = 0;
public interface OnSoftKeyboardListener {
void showKeyboard(int keyboardHeight, int diff);
void hideKeyboard(int keyboardHeight);
}
public static void registerListener(@NotNull Activity activity, @NotNull OnSoftKeyboardListener listener) {
lastVisibleHeight = 0;
View rootView = activity.getWindow().getDecorView();
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();
rootView.getWindowVisibleDisplayFrame(rect);
int visibleHeight = rect.height();
if (lastVisibleHeight == 0) {
lastVisibleHeight = visibleHeight;
} else {
if (lastVisibleHeight > visibleHeight) {
int keyboardHeight = lastVisibleHeight - visibleHeight;
if (keyboardHeight > 200) {
listener.showKeyboard(keyboardHeight, visibleHeight);
lastVisibleHeight = visibleHeight;
}
} else if (lastVisibleHeight < visibleHeight) {
int keyboardHeight = visibleHeight - lastVisibleHeight;
if (keyboardHeight > 200) {
listener.hideKeyboard(keyboardHeight);
lastVisibleHeight = visibleHeight;
}
}
}
}
});
}
}
XML布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".LoginActivity">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="120dp"
android:src="@mipmap/ic_launcher_round" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="300dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="35dp"
android:layout_height="35dp"
android:src="@drawable/user" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入用户名" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="35dp"
android:layout_height="35dp"
android:src="@drawable/pwd" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入密码" />
</LinearLayout>
<Button
android:id="@+id/confirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="确定" />
<RelativeLayout
android:id="@+id/help"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:text="忘记密码" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="注册" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="联系客服" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:text="|" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关于我们" />
</LinearLayout>
</RelativeLayout>
逻辑代码
class LoginActivity2 : AppCompatActivity() {
private lateinit var root: RelativeLayout
private lateinit var help: View
private lateinit var confirm: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login2)
root = findViewById(R.id.root)
help = findViewById(R.id.help)
confirm = findViewById(R.id.confirm)
SoftKeyboardListener.registerListener(this, object : OnSoftKeyboardListener {
override fun showKeyboard(keyboardHeight: Int, diff: Int) {
root.scrollTo(0, help.bottom - diff)
}
override fun hideKeyboard(keyboardHeight: Int) {
root.scrollTo(0, 0)
}
})
}
}
方式二:使用NestedScrollView
scrollTo比较生硬,使用NestedScrollView + 动画会有一个滑动效果。
XML布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".LoginActivity">
<ImageView
android:id="@+id/logo"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="120dp"
android:src="@mipmap/ic_launcher_round" />
<androidx.core.widget.NestedScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbarThumbVertical="@android:color/transparent"
android:scrollbars="vertical">
<LinearLayout
android:id="@+id/wrapper"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="300dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="35dp"
android:layout_height="35dp"
android:src="@drawable/user" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入用户名" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="35dp"
android:layout_height="35dp"
android:src="@drawable/pwd" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入密码" />
</LinearLayout>
<Button
android:id="@+id/confirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="确定" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:text="忘记密码" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="注册" />
</RelativeLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<LinearLayout
android:id="@+id/helper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="联系客服" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:text="|" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关于我们" />
</LinearLayout>
</RelativeLayout>
逻辑代码
class LoginActivity : AppCompatActivity() {
private lateinit var scrollView: NestedScrollView
private lateinit var helper: LinearLayout
private lateinit var wrapper: LinearLayout
private lateinit var logo: ImageView
private lateinit var confirm: Button
private var screenHeight = 0
private var keyboardHeight = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
BarUtils.setTransparentStatusBar(this)
scrollView = findViewById(R.id.scrollView)
helper = findViewById(R.id.helper)
wrapper = findViewById(R.id.wrapper)
logo = findViewById(R.id.logo)
confirm = findViewById(R.id.confirm)
confirm.setOnClickListener { KeyboardUtils.hideKeyboard(confirm) }
screenHeight = Resources.getSystem().displayMetrics.heightPixels
keyboardHeight = screenHeight / 3
scrollView.setOnTouchListener { v, event -> true }
scrollView.addOnLayoutChangeListener { v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom ->
if (oldBottom != 0 && bottom != 0) {
if ((oldBottom - bottom) > keyboardHeight) {
val diff = wrapper.bottom - bottom
if (diff > 0) {
AnimatorUtils.translationY(wrapper, 0F, (-diff).toFloat())
AnimatorUtils.scale(logo, 1F, 0.6F)
}
helper.visibility = View.INVISIBLE
} else if ((bottom - oldBottom) > keyboardHeight) {
val diff = wrapper.bottom - oldBottom
if (diff > 0) {
AnimatorUtils.translationY(wrapper, wrapper.translationY, 0F)
AnimatorUtils.scale(logo, 0.6F, 1F)
}
helper.visibility = View.VISIBLE
}
}
}
}
}
动画
object AnimatorUtils {
fun translationY(view: View, from: Float, to: Float) {
ObjectAnimator.ofFloat(view, TRANSLATION_Y, from, to).apply {
duration = 300L
}.start()
}
fun scale(view: View, fromScale: Float, toScale: Float) {
view.apply {
pivotX = (view.width / 2).toFloat()
pivotY = (view.height / 2).toFloat()
}
val animatorScaleX = ObjectAnimator.ofFloat(view, SCALE_X, fromScale, toScale)
val animatorScaleY = ObjectAnimator.ofFloat(view, SCALE_Y, fromScale, toScale)
AnimatorSet().apply {
duration = 300L
playTogether(animatorScaleX, animatorScaleY);
}.start()
}
}
|