在项目开发中遇到这样一个问题,当用户输入某些数据时,我们接下来是进行数据操作,这时候为了让用户有更好的交互感,所以我们需要布局中的某一块布局进行整体上移,增加用户体验,故有了此篇文章,请往下看 ~
1.在AndroidManifest中找到对应的activity,加入 android:windowSoftInputMode="stateHidden|adjustPan"
2.在代码中,我们需要俩个视图id,其中一个为最外层布局,另一个为要顶起的布局,其他布局方式与平常无异
第一种方式
1.最外层为自定义的ScrollView ,注意设置 android:fillViewport="true"
,其意义在于让子布局展示完整
2.使用ScrollView 的同时要注意其只能包含一个子View,所以你需要在嵌套一层LinearLayout或者RelativeLayout
3.在 onResume 生命周期内 设置 mRootView.addOnLayoutChangeListener(this);
4.使用Runnable做延迟操作
5.主要思想在于通过键盘的弹起状态,设置对应的MarginBottom属性距离
SlowScrollView (这个自定义类主要作用于减缓滑动的速度,找自网上,可直接Copy):
package com.example.yongliu.keyboardrecord;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;
import android.widget.Scroller;
/**
* @author yongliu
* date 2018/3/27.
* desc:
*/
public class SlowScrollView extends ScrollView {
private Scroller mScroller;
public SlowScrollView(Context context) {
super(context);
mScroller = new Scroller(context);
}
public SlowScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
}
public SlowScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mScroller = new Scroller(context);
}
/**
* 调用此方法滚动到目标位置 duration滚动时间
*/
public void smoothScrollToSlow(int fx, int fy, int duration) {
//mScroller.getFinalX(); 普通view使用这种方法
int dx = fx - getScrollX();
//mScroller.getFinalY();
int dy = fy - getScrollY();
//this.setOverScrollMode(OVER_SCROLL_ALWAYS);
smoothScrollBySlow(dx, dy, duration);
}
/**
* 调用此方法设置滚动的相对偏移
*/
public void smoothScrollBySlow(int dx, int dy, int duration) {
//设置mScroller的滚动偏移量
mScroller.startScroll(getScrollX(), getScrollY(), dx, dy, duration);
//scrollView使用的方法(因为可以触摸拖动)
//mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy, duration); //普通view使用的方法
//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
invalidate();
}
@Override
public void computeScroll() {
//先判断mScroller滚动是否完成
if (mScroller.computeScrollOffset()) {
//这里调用View的scrollTo()完成实际的滚动
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
//必须调用该方法,否则不一定能看到滚动效果
postInvalidate();
}
super.computeScroll();
}
/**
* 滑动事件,这是控制手指滑动的惯性速度
*/
@Override
public void fling(int velocityY) {
super.fling(velocityY / 4);
}
}
MainActivity :
package com.example.yongliu.keyboardrecord;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity implements View.OnLayoutChangeListener {
private LinearLayout mOutView;
private SlowScrollView mRootView;
private int screenHeight;
private int keyHeight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRootView = findViewById(R.id.root_view);
mOutView = findViewById(R.id.ll_out_view);
//获取屏幕高度
screenHeight = getWindowManager().getDefaultDisplay().getHeight();
//阀值设置为屏幕高度的1/3
keyHeight = screenHeight / 3;
}
@Override
protected void onResume() {
super.onResume();
mRootView.addOnLayoutChangeListener(this);
}
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
//获取View可见区域的bottom
Rect rect = new Rect();
this.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
if (bottom != 0 && oldBottom != 0 && bottom - rect.bottom <= 0) {
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mOutView.getLayoutParams();
params.bottomMargin = 2;
mOutView.setLayoutParams(params);
Log.e("tag", "收起");
} else {
Handler handler = new Handler();
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mOutView.getLayoutParams();
params.bottomMargin = keyHeight + keyHeight / 2;
mOutView.setLayoutParams(params);
//缓慢移动,防止太快造成交互体验差的感觉
handler.postDelayed(runnable, 100);
Log.e("tag", "弹出");
}
}
private Runnable runnable = new Runnable() {
@Override
public void run() {
// 改变滚动条的位置
mRootView.smoothScrollToSlow(0, keyHeight, 100);
}
};
}
MainActivity Xml :
<com.example.yongliu.keyboardrecord.SlowScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:fillViewport="true"
android:orientation="vertical"
android:scrollbars="none"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ImageView
android:id="@+id/iv_icon"
android:layout_width="match_parent"
android:layout_height="240dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
/>
<LinearLayout
android:id="@+id/ll_out_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:orientation="vertical"
android:paddingBottom="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="#fff"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="45dp"
android:gravity="center"
android:text="手机号:"
android:textColor="#363636"
android:textSize="16sp"/>
<EditText
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:layout_weight="1"
android:background="@null"
android:gravity="center_vertical"
android:hint="请输入你的手机号"
android:inputType="number"
android:maxLength="11"
android:singleLine="true"
android:textSize="16sp"/>
LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="45dp"
android:layout_marginRight="45dp"
android:background="#363636"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="#fff"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="45dp"
android:gravity="center"
android:text="密码:"
android:textColor="#363636"
android:textSize="16sp"/>
<EditText
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="30dp"
android:layout_weight="1"
android:background="@null"
android:gravity="center_vertical"
android:hint="请输入你的密码"
android:inputType="number"
android:maxLength="11"
android:singleLine="true"
android:textSize="16sp"/>
LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="45dp"
android:layout_marginRight="45dp"
android:layout_marginTop="2dp"
android:background="#363636"/>
LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="登录"
android:textSize="14sp"/>
LinearLayout>
LinearLayout>
com.example.yongliu.keyboardrecord.SlowScrollView>
第二种方式 (相比第一种方式,这种方式显得更自然一些~):
这里在使用中发现了一个bug,如果有视图在我们获焦或者失焦的时候,有触发View.Gone 或者 View .Visible 属性的话,键盘弹起功能会失效,所以这里如果需要隐藏某一个视图的话,我们就用View . Invisible
MainActivity :
package com.example.yongliu.keyboardrecord;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
// implements View.OnLayoutChangeListener {
public class MainActivity extends AppCompatActivity{
private LinearLayout mOutView;
private LinearLayout mRootView;
//设置一个默认值
private int recordVisibleRec = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//最外层布局
mRootView = findViewById(R.id.root_view);
//想要顶起的布局块
mOutView = findViewById(R.id.ll_out_view);
controlKeyboardLayout(mRootView, mOutView);
}
/**
* @param root 最外层布局,需要调整的布局
* @param scrollToView 被键盘遮挡的scrollToView,滚动root,使scrollToView在root可视区域的底部
*/
private void controlKeyboardLayout(final View root, final View scrollToView) {
root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();
//获取root在窗体的可视区域
root.getWindowVisibleDisplayFrame(rect);
//获取root在窗体的不可视区域高度(被其他View遮挡的区域高度)
int rootInvisibleHeight = root.getRootView().getHeight() - rect.bottom;
if (Math.abs(rootInvisibleHeight - recordVisibleRec) > 200) {
//若不可视区域高度大于200,则键盘显示
if (rootInvisibleHeight > 200) {
int[] location = new int[2];
//获取scrollToView在窗体的坐标
scrollToView.getLocationInWindow(location);
//计算root滚动高度,使scrollToView在可见区域
int srollHeight = (location[1] + scrollToView.getHeight()) - rect.bottom;
srollHeight = srollHeight < 0 ? 0 : srollHeight;
root.scrollTo(0, srollHeight);
} else {
//键盘隐藏
root.scrollTo(0, 0);
}
}
recordVisibleRec = rootInvisibleHeight;
}
});
}
}
MainActivity Xml :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:fillViewport="true"
android:orientation="vertical"
android:scrollbars="none"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ImageView
android:id="@+id/iv_icon"
android:layout_width="match_parent"
android:layout_height="240dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
/>
<LinearLayout
android:id="@+id/ll_out_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:orientation="vertical"
android:paddingBottom="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="#fff"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="45dp"
android:gravity="center"
android:text="手机号:"
android:textColor="#363636"
android:textSize="16sp"/>
<EditText
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:layout_weight="1"
android:background="@null"
android:gravity="center_vertical"
android:hint="请输入你的手机号"
android:inputType="number"
android:maxLength="11"
android:singleLine="true"
android:textSize="16sp"/>
LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="45dp"
android:layout_marginRight="45dp"
android:background="#363636"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="#fff"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="45dp"
android:gravity="center"
android:text="密码:"
android:textColor="#363636"
android:textSize="16sp"/>
<EditText
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="30dp"
android:layout_weight="1"
android:background="@null"
android:gravity="center_vertical"
android:hint="请输入你的密码"
android:inputType="number"
android:maxLength="11"
android:singleLine="true"
android:textSize="16sp"/>
LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="45dp"
android:layout_marginRight="45dp"
android:layout_marginTop="2dp"
android:background="#363636"/>
LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="登录"
android:textSize="14sp"/>
LinearLayout>
LinearLayout>
LinearLayout>