Android进阶之路 - 监听软键盘当前状态,实现布局上移_android软键盘弹出布局上移-程序员宅基地

技术标签: 键盘顶起布局  软键盘  # 项目开发知识点归纳  Android  

在项目开发中遇到这样一个问题,当用户输入某些数据时,我们接下来是进行数据操作,这时候为了让用户有更好的交互感,所以我们需要布局中的某一块布局进行整体上移,增加用户体验,故有了此篇文章,请往下看 ~

我的那些软键盘Blog ~

关于软键盘顶起布局的方式,该篇总共使用了俩种方式,俩者主要区别在于用户体验方面 ~

公共注意点

  • 在AndroidManifest中找到对应的activity,加入android:windowSoftInputMode="stateHidden|adjustPan"

  • 在代码中,我们需要俩个视图id,其中一个为最外层布局,另一个为要顶起的布局,其他布局方式与平常无异

Effect(面临的问题)
这里写图片描述


第一种方式
  • Effect
    这里写图片描述

注意点

  • 最外层为自定义的ScrollView ,注意设置 android:fillViewport="true",其意义在于让子布局展示完整
  • 使用ScrollView 的同时要注意其只能包含一个子View,所以你需要在嵌套一层LinearLayout或者RelativeLayout
  • 在 onResume 生命周期内 设置 mRootView.addOnLayoutChangeListener(this);
  • 使用Runnable做延迟操作
  • 主要思想在于通过键盘的弹起状态,设置对应的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);
        }
    };
}

activity_main :

<?xml version="1.0" encoding="utf-8"?>
<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>

第二种方式

相比第一种方式,这种方式显得更自然一些~

  • Effect
    这里写图片描述

注意点

这里在使用中发现了一个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;
            }
        });
    }
}

activity_main:

<?xml version="1.0" encoding="utf-8"?>
<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"
            >
            <!--android:layout_marginBottom="320dp"-->

            <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>
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_20451879/article/details/79853154

智能推荐

基于Java在线电影票购买系统设计实现(源码+lw+部署文档+讲解等)-程序员宅基地

文章浏览阅读4.1k次,点赞2次,收藏4次。社会和科技的不断进步带来更便利的生活,计算机技术也越来越平民化。二十一世纪是数据时代,各种信息经过统计分析都可以得到想要的结果,所以也可以更好的为人们工作、生活服务。电影是生活娱乐的一部分,特别对喜欢看电影的用户来说是非常重要的事情。把计算机技术和影院售票相结合可以更符合现代、用户的要求,实现更为方便的购买电影票的方式。本基于Java Web的在线电影票购买系统采用Java语言和Vue技术,框架采用SSM,搭配MySQL数据库,运行在Idea里。

集合的addAll方法--list.addAll(null)会报错--java.lang.NullPointerException-程序员宅基地

文章浏览阅读1.8k次。Exception in thread "main" java.lang.NullPointerException at java.util.ArrayList.addAll(ArrayList.java:559) at com.iflytek.epdcloud.recruit.utils.quartz.Acool.main(Acool.java:16)import java.u..._addall(null)

java获取当天0点到24点的时间戳,获得当前分钟开始结束时间戳_java 获取某分钟的起止时间戳-程序员宅基地

文章浏览阅读4.5k次。public static void main(String[] args) { Calendar todayStart = Calendar.getInstance(); todayStart.set(Calendar.HOUR_OF_DAY, 0); todayStart.set(Calendar.MINUTE, 0); toda..._java 获取某分钟的起止时间戳

北京内推 | 京东AI研究院计算机视觉实验室招聘三维视觉算法研究型实习生-程序员宅基地

文章浏览阅读1.1k次。合适的工作难找?最新的招聘信息也不知道?AI 求职为大家精选人工智能领域最新鲜的招聘信息,助你先人一步投递,快人一步入职!京东 AI 研究院京东 AI 研究院(https://air.jd..._京东计算机视觉实验室

Ubuntu18.04安装配置Qt5.15_ubuntu安装qt5.15-程序员宅基地

文章浏览阅读2.1k次。Ubuntu18.04安装配置Qt5.15 Ubuntu18.04安装配置Qt5.15 Qt选择下载Qt安装Qt5.15.0配置后记 Qt选择 在官方的声明中,Qt5.15是Qt5.x的最后一个LTS版本,增加了即将在2020年底推出的Qt6的部分新特性,为了之后的新_ubuntu安装qt5.15

针对Error: You must either define the environment variable DJANGO_SETTINGS_MODULE ...问题的解决_project structure->facets->django->-程序员宅基地

文章浏览阅读1.8w次,点赞5次,收藏3次。针对Error: You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings问题的解决使用intelliJ Idea开发django项目,启动 manage.py 测试时,会出现如上所示问题。根据提示,有两种解_project structure->facets->django->

随便推点

rufus 一款好用的linux u盘,光盘刻录工具_rufus可以刻录光盘吗-程序员宅基地

文章浏览阅读2.2k次。rufus 一款好用的linux u盘,光盘刻录工具:下载(点击普通下载中的“立即下载”): http://share.cnop.net/file/1806028-401886318_rufus可以刻录光盘吗

用VB.net实现对.ini文件的读写操作的类-程序员宅基地

文章浏览阅读142次。Option Explicit OnModule INI 'INICont.bas Ver 1.0+a INI '==================================================================== 'GetIntFromINI( sectionName , keyName , defaultValue, iniPath ) '..._vb.net 读取ini文件 int

linux集群—负载均衡集群LBC_lbc在程序中是什么-程序员宅基地

文章浏览阅读615次。1 集群的定义集群的出现主要是为了解决单台设备性能不足、效率低下等问题,可以保证业务无中断,总体效率高,适合大型业务。2 集群的分类3 负载均衡集群LBC_lbc在程序中是什么

【渝粤题库】陕西师范大学200161 文字学概论 作业_十小羊未哪一个不是象形字-程序员宅基地

文章浏览阅读3k次。《文字学概论》作业一、单选题1、原始社会陶器上的图形符号刻划是以( )为代表的。A 仰韶文化 B 马家窑文化 C 良渚文化 D 大汶口文化2、下列各字中不属于象形字的是( )。A十 B小 C羊 D未3、“画成弃物 ,随体诘屈”,是许慎给六书当中的( )所下的定义。A 象形 B 指事 C 假借 D 会意4、下列各字当中形旁为"肉”的是( )。A 肌 B 明 C 钥 D 腾5、“夫” 字是在“大”字之上加一横而成的,这_十小羊未哪一个不是象形字

tiny_tds: 简易的Microsoft SQL Server驱动程序 for Ruby-程序员宅基地

文章浏览阅读328次,点赞9次,收藏8次。tiny_tds: 简易的Microsoft SQL Server驱动程序 for Rubytiny_tds 是一个小巧且高效的Microsoft SQL Server驱动程序,专为Ruby编程语言设计。它提供了与SQL Server进行交互的能力,可以轻松地执行查询、事务管理以及数据操作。项目简介tiny_tds是一个开源项目,由Rails SQL Server社区开发并维护。该库支持多种...

高性能mysql第五版在线阅读_MySQL零基础入门推荐书籍(收藏版)-程序员宅基地

文章浏览阅读8.6k次。1,基础篇:1.1《SQL基础教程》本书是畅销书《SQL基础教程》第2版,介绍了关系数据库以及用来操作关系数据库的SQL语言的使用方法。书中通过丰富的图示、大量示例程序和详实的操作步骤说明,让读者循序渐进地掌握SQL的基础知识和使用技巧,切实提高编程能力。每章结尾设置有练习题,帮助读者检验对各章内容的理解程度。另外,本书还将重要知识点总结为“法则”,方便读者随时查阅。第2版除了将示例程序更新为对应..._高性能mysql第五版 pdf

推荐文章

热门文章

相关标签