当前位置: 移动技术网 > IT编程>移动开发>Android > Android 开发之Dialog中隐藏键盘的正确使用方法

Android 开发之Dialog中隐藏键盘的正确使用方法

2019年07月24日  | 移动技术网IT编程  | 我要评论

青青诛仙,加油菊花国语版,流氓公爵

android 开发之dialog中隐藏键盘的正确使用方法

场景:弹出一个dialog,里面有一个edittext,用来输入内容,因为输入时,需要弹出键盘,所以当dialog消失时,键盘要一起隐藏。

现在我们做一个自定义的dialog

mydialog extends dialog 

一开始认为这个功能很容易实现,于是写了下面的代码

//dialog的构造函数中写 
  this.setondismisslistener(new ondismisslistener() { 
   @override 
   public void ondismiss(dialoginterface dialog) { 
    hidekeyboard(); 
   } 
  }); 
//edcontent是输入框 
 public void hidekeyboard(){ 
  inputmethodmanager inputmethodmanager = (inputmethodmanager) getcontext().getsystemservice(context.input_method_service); 
  inputmethodmanager.hidesoftinputfromwindow(edcontent.getwindowtoken(), inputmethodmanager.hide_not_always); 
 } 

运行之后,发现根本无法隐藏,看看hidesoftinputfromwindow中干了啥

public boolean hidesoftinputfromwindow(ibinder windowtoken, int flags, 
    resultreceiver resultreceiver) { 
  checkfocus(); 
  synchronized (mh) { 
    if (mservedview == null || mservedview.getwindowtoken() != windowtoken) { 
      return false; 
    } 
 
    try { 
      return mservice.hidesoftinput(mclient, flags, resultreceiver); 
    } catch (remoteexception e) { 
    } 
    return false; 
  } 
} 

跟踪进去发现参数 windowtoken 是 null,而且 mservedview 也是null,所以直接返回false,无法隐藏。

也就是说,你监听cancel或者dismiss都是不行的,因为此时dialog已经消失,用于输入的服务窗体已经是null了,所以你要想 隐藏键盘,就需要在dismiss之前处理,那这个入口在哪呢?

为了当点击空白处时,可以隐藏dialog,所以我们在构造函数中加了一句话

this.setcanceledontouchoutside(true); 

所以当我们点击空白区域时,会触发dialog的ontouchevent

public boolean ontouchevent(motionevent event) { 
  if (mcancelable && mshowing && mwindow.shouldcloseontouch(mcontext, event)) { 
    cancel(); 
    return true; 
  } 
   
  return false; 
} 

这里会调用基类window的shouldcloseontouch方法,来判断是否可以关闭,这里我们看到如果满足,就直接cancel()了,

public void cancel() { 
  if (!mcanceled && mcancelmessage != null) { 
    mcanceled = true; 
    // obtain a new message so this dialog can be re-used 
    message.obtain(mcancelmessage).sendtotarget(); 
  } 
  dismiss(); 
} 

这里面就会dismiss掉dialog,所以我们发现,在dismiss前,我们根本无法干预,真是个悲剧。所以我们只能重载ontouchevent方法,并且自己判断是否可以关闭(也就是把下面代码迁移到你的代码中!

public boolean shouldcloseontouch(context context, motionevent event) { 
  if (mcloseontouchoutside && event.getaction() == motionevent.action_down 
      && isoutofbounds(context, event) && peekdecorview() != null) { 
    return true; 
  } 
  return false; 
} 
 
private boolean isoutofbounds(context context, motionevent event) { 
  final int x = (int) event.getx(); 
  final int y = (int) event.gety(); 
  final int slop = viewconfiguration.get(context).getscaledwindowtouchslop(); 
  final view decorview = getdecorview(); 
  return (x < -slop) || (y < -slop) 
      || (x > (decorview.getwidth()+slop)) 
      || (y > (decorview.getheight()+slop)); 
} 

自己代码中这样

@override 
public boolean ontouchevent(motionevent event) { 
 if (isshowing() && shouldcloseontouch(getcontext(),event)){ 
  hidekeyboard(); 
 } 
 return super.ontouchevent(event); 
} 
public boolean shouldcloseontouch(context context, motionevent event) { 
 if (event.getaction() == motionevent.action_down 
     && isoutofbounds(context, event) && getwindow().peekdecorview() != null) { 
  return true; 
 } 
 return false; 
} 
private boolean isoutofbounds(context context, motionevent event) { 
 final int x = (int) event.getx(); 
 final int y = (int) event.gety(); 
 final int slop = viewconfiguration.get(context).getscaledwindowtouchslop(); 
 final view decorview = getwindow().getdecorview(); 
 return (x < -slop) || (y < -slop) 
     || (x > (decorview.getwidth()+slop)) 
     || (y > (decorview.getheight()+slop)); 
} 

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网