欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-18 22:34:22
android 开发之dialog中隐藏键盘的正确使用方法 场景:弹出一个dialog,里面有一个edittext,用来输入内容,因为输入时,需要弹出键盘,所以当dial...

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)); 
} 

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

上一篇:

下一篇: