一:EditText为什么会默认d出输入法
同样的代码,碰到有EditText控件的界面时有的机子会d出输入法,有的机子不会d出。不好意思,这问题我也一头雾水,谁知道可以告诉我,否则我就把这个问题留下来,以后研究android源码时再搞个清楚。但是我有解决方案。
二:默认d出和默认关闭输入法的解决方案。
1默认关闭,不至于进入Activity就打开输入法,影响界面美观。
①在布局文件中,在EditText前面放置一个看不到的LinearLayout,让他率先获取焦点:
[html] view plaincopyprint
01<LinearLayout
02
03android:focusable="true"
04
05android:focusableInTouchMode="true"
06
07android:layout_width="0px"
08
09android:layout_height="0px"/>
<LinearLayout
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_width="0px"
android:layout_height="0px"/>
②方法二:先看一个属性android:inputType:指定输入法的类型,int类型,可以用|选择多个。取值可以参考:androidtextInputType类。取值包括:text,textUri,
phone,number,等
Android SDK中有这么一句话“If
the given content type is TYPE_NULL then a soft keyboard will not be displayed for this text view”,
先将EditText的InputType改变为TYPE_NULL,输入法就不会d出然后再设置监听,再重新设置它的InputType
[java] view plaincopyprint
01editTextsetOnTouchListener(new OnTouchListener() {
02 public boolean onTouch(View v, MotionEvent event) {
03 // TODO Auto-generated method stub
04 int inType = editTextgetInputType(); // backup the input type
05 editTextsetInputType(InputTypeTYPE_NULL); // disable soft input
06 editTextonTouchEvent(event); // call native handler
07 editTextsetInputType(inType); // restore input type
08 return true;
09 }
10 });
editTextsetOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
int inType = editTextgetInputType(); // backup the input type
editTextsetInputType(InputTypeTYPE_NULL); // disable soft input
editTextonTouchEvent(event); // call native handler
editTextsetInputType(inType); // restore input type
return true;
}
});
2默认d出。有时候按照需求可能要求默认d出输入法。方案如下:
[java] view plaincopyprint
01EditText titleInput = (EditText) findViewById(Ridcreate_edit_title);titleInputsetFocusable(true);
02
03 titleInputrequestFocus();
04 onFocusChange(titleInputisFocused());
05
06private void onFocusChange(boolean hasFocus)
07{
08final boolean isFocus = hasFocus;
09(new Handler())postDelayed(new Runnable() {
10public void run() {
11InputMethodManager imm = (InputMethodManager)
12titleInputgetContext()getSystemService(ContextINPUT_METHOD_SERVICE);
13if(isFocus)
14{
15immtoggleSoftInput(0, InputMethodManagerHIDE_NOT_ALWAYS);
16}
17else
18{
19immhideSoftInputFromWindow(titleInputgetWindowToken(),0);
20}
21}
22}, 100);
23}
EditText titleInput = (EditText) findViewById(Ridcreate_edit_title);titleInputsetFocusable(true);
titleInputrequestFocus();
onFocusChange(titleInputisFocused());
private void onFocusChange(boolean hasFocus)
{
final boolean isFocus = hasFocus;
(new Handler())postDelayed(new Runnable() {
public void run() {
InputMethodManager imm = (InputMethodManager)
titleInputgetContext()getSystemService(ContextINPUT_METHOD_SERVICE);
if(isFocus)
{
immtoggleSoftInput(0, InputMethodManagerHIDE_NOT_ALWAYS);
}
else
{
immhideSoftInputFromWindow(titleInputgetWindowToken(),0);
}
}
}, 100);
}
我觉得因为在Android的主线程中对UI的 *** 作无效,所以必须在Handler中实现d出输入法的 *** 作
三。关于焦点和输入法的个人理解
获取焦点是获取焦点,d输入法是d输入法。获取焦点后并不一定会d出输入法,在网上搜了一圈,主流回答是“还有就是已开启界面就是focus的text的话有可能也是不行的,UI渲染是需要时间的”
由于对源码不懂,我对这一点也没有个全面的认识。只能将焦点和输入法分成两块来处理。焦点的打开和关闭特别简单。
焦点的获取:
titleInputsetFocusable(true);
titleInputrequestFocus();
焦点的取消:
titleInputsetFocusable(false); 四。关于经常调用的处理软键盘的函数如下:<转载>
1、打开输入法窗口:
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(ContextINPUT_METHOD_SERVICE);
// 接受软键盘输入的编辑文本或其它视图
immshowSoftInput(submitBt,InputMethodManagerSHOW_FORCED);
2、关闭出入法窗口
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(ContextINPUT_METHOD_SERVICE);
inputMethodManagerhideSoftInputFromWindow(OpeListActivitythisgetCurrentFocus()getWindowToken(),
InputMethodManagerHIDE_NOT_ALWAYS);
//接受软键盘输入的编辑文本或其它视图
inputMethodManager
showSoftInput(submitBt,InputMethodManagerSHOW_FORCED);
3、如果输入法打开则关闭,如果没打开则打开
InputMethodManager m=(InputMethodManager) getSystemService(ContextINPUT_METHOD_SERVICE);
mtoggleSoftInput(0, InputMethodManagerHIDE_NOT_ALWAYS);
4、获取输入法打开的状态
InputMethodManager imm = (InputMethodManager)getSystemService(ContextINPUT_METHOD_SERVICE);
boolean isOpen=immisActive();
isOpen若返回true,则表示输入法打开
转载
第一、确定测试目标。
在没有明显的帮助的情况下启动和使用应用程序;应用中的任务流程都能够很容易地导航并且会提供清晰适当的反馈。
第二、不可缺少的测试。
1 方向键。确认应用能够在无触摸屏的情况下 *** 作,尝试在只使用方向键的情况下完成应用中的主要任务。使用模拟器中的键盘及方向盘,或者在41以上的设备中使用手势导航来 *** 作设备。
2对话语音提示。确保提供信息或者允许用户 *** 作的UI控件在TalkBack is enabled并且该控件获得焦点时都有清晰准确的语音描述。用户可以使用定向控制在应用的布局间移动焦点。
3触控浏览提示。确保提供信息或者允许用户 *** 作的UI控件在Explore by Touch is enabled时都有清晰准确的语音描述。每个地方的内容或者控件都应该有语音描述。
4触控区大小。所有用户可以选择和执行 *** 作的控件在长度和宽度上都应该至少有48dp(大约9mm),正如Android Design中推荐的做法。
5语音提示下使用手势。确保应用中使用的手势,如缩放,滑动列表,页面间切换等在TalkBack is enabled的情况下能继续正常工作。如果这些手势不起作用,你应该为这些动作提供一个替代的 *** 作方式。
6不应该只有声音反馈。声音反馈必须同时有另外一套反馈机制来供耳聋用户使用。例如,收到短信后发出声音提醒的同时应该也发送一条系统通知,震动反馈或者其它的视觉提醒。
第三、测试建议
1重复语音提示:密切相关的控件(比如一个列表中有多项内容的一栏)不应该重复相同的语音提示。例如,在一个包含联系人、姓名、职位的联系人列表中,不应该对每一项都只是重复地提示"Bob Smith"。
2语音提示过多或者过少:密切相关的控件应该提供适当的语音提示以保证用户明白并能 *** 作屏幕上的元素,太多或者太少提示会让用户难以理解及使用控件。
第四、应该考虑的特殊情况。
1检查无障碍功能开发的special cases并且测试需要测试的情况。
2如果由于应用流程导致按钮或者其它控件改变了功能,那么必须为控件的当前功能作出适当的语音提示。例如,一个按钮的功能由播放视频变为暂停视频,那么必须作出适当的语音提示来表明当前的状态。
3如果一个应用提供视频播放,那么确保它支持字幕并提供字幕以帮助听障人士。视频的播放控制必须明确地标明字幕是否可用并且提供方便的方式启用
title: '深入理解android2-WMS,控件-图床版'
date: 2020-03-08 16:22:42
tags:
typora-root-url: /深入理解android2-WMS-控件
typora-copy-images-to: /深入理解android2-WMS-控件
WMS主要负责两个功能, 一是负责窗口的管理,如窗口的增加删除,层级二是负责全局事件的派发如触摸点击事件
先简单介绍几个重要的类
IWindowSession 进程唯一的是一个匿名binder通过他向WMS请求窗口 *** 作
surface 绘画时,canvas会把内容绘制到surface里surface是有surfaceFlinger提供给客户端的
WindowManagerLayoutParams 集成自ViewGroupLayoutParams用来指明client端的窗口的一些属性最重要的是type 根据这属性来对多个窗口进程ZOrder的排序
windowToken向WMS添加的窗口令牌每个窗口都要有一个令牌
IWindow 是client提供给WMS的继承自binderWMS通过IWindow对象来主动发起client端的事件
窗口的本周就是进行绘制所使用的surface,客户端向WMS添加窗口的过程,就是WMS为客户端分配surface的过程
ui框架层就是使用surface上绘制ui元素及响应输入事件
WMS负责surface的分配窗口的层级顺序
surfaceFlinger负责将多个Surface混合并输出
WMS有SystemServer 进程启动他和AMS其实是运行于一个进程中的只是分别有各自的线程
上边传入了两个handler这里就使用windowManager的handler来创建WMS也就是在一个handerThread线程中创建
用来管理每个窗口的事件输入也就是把输入事件转发到正确的窗口
能获取显示系统的同步信号用来驱动动画的渲染
所有窗口动画的总管,在mChoreographer的驱动下渲染所有动画
只有PhoneWindowManager一个实现定义了很多窗口相关的策略是最重要的成员,比如负责窗口的zorder顺序
zorder就是各个窗口在z轴的值越大越在屏幕上层窗口就是根据zorder值一层一层堆在一起
可以绘制的屏幕列表默认是只有1个
管理所以窗口的显示令牌token,每个窗口都要属于一个token这里的IBinder 是
表示所有Activity的token AppWindowToken是WindowToken的子类,这个list的顺序和AMS中对mHistory列表中activity的顺序是一样的 反应了系统中activity的叠加顺序也就是说所有窗口都有WindowToken而Activity对应的窗口则多了AppWindowToken
每个窗口都对应一个WindowState存储改窗口的状态信息(这就和AMS中对每个activity抽象成ActivityRecord一样)
这里的iBinder 是IWIndow类
Session 是WMS提供给客户端来与WMS进行交互的,这是匿名binder为了减轻WMS的负担客户端通过IWindowManageropenSession 拿到他的代理然后通过代理与WMS交互每个进程唯一
客户端通过IWindowSessionadd 来添加窗口 iWindowSession 是同aidl形成的最终到了WMSaddWindow
这里总的来说就是确立了客户窗口的WindowTokenWindowState和DisplayContent 并都保存了起来同时根据layoutparamstype进行了些窗口等级的判断
WindowToken将同一个应用组件的窗口安排在一起一个应用组件可以是Activity,InputMethod
WindowToken使应用组件在变更窗口时必须与自己的WindowToken匹配
这里主要是为了处理窗口的层级关系而设立的
只要是一个binder对象都可以作为token向wms声明wms会把这个binder对应起一个WindowToken其实就是把客户端的binder和wms里的一个WindowToken对象进行了绑定
因为Activity比较复杂,因此WMS为Activity实现了WindowToken的子类 appwindowtoken同时在AMS启动Activity的ActivityStackstartActivityLocked里声明token
然后在activityStackrealStartActivityLocked里在发给用户进程,然后用户在通过这个binder和WMS交互时带过来
activity则在 activityStack 线程的handleResumeActivity 里把Activity 对应的窗口,加入到wMS中
取消token 也是在AMS中 ,也就是说, AMS负责avtivity的token向WMS的添加和删除
当然Activity的 rappToken 是 IApplicationTokenStub ,他里边有一系列的窗口相关的通知回调
这里总结下 AMS在创建Activity的ActivityRecord时,创建了他的appToken,有把appToken传送给WMSWMS对应匹配为APPWindowToken,最后还把这个appToken发送给activity因此AMS就通过ActivityRecord就可有直接 *** 作WMS对该窗口的绘制如图
每个window在WMS里都抽象成了WindowState他包含一个窗口的所有属性WindowState在客户端对应的则是iWidowstub类iWidowstub有很多窗口通知的回调
WindowState被保存在mWindowMap里这是整个系统所有窗口的一个全集
HashMap<IBinder, WindowToken> mTokenMap 这里是 IApplicationToken(客户端)和WindowToken的映射
HashMap<IBinder, WindowState> mWindowMap 这里是IWidow(客户端)和WindowState的映射,并且WMS通过这个IWindow 来回调客户端的方法
上图可以看出每个activity 只有一个ActivityRecord也只有一个AppToken,也就只有一个WindowToken而一个acitvity可能有多个窗口每个窗口对应一个WindowState
WindowToken用来和AMS交换 而WindowState对应的iWindow则是WMS来与客户端交互的
窗口显示次序就是窗口在Z轴的排了因为窗口是叠加在一起的因此就需要知道哪些显示在上边,哪些在下边这个由WindowState构造时确定
可见分配规则是由WindowManagerPolicy mPolicy来决定的产生 mBaseLayer和mSubLayer mBaseLayer决定该窗口和他的子窗口在所有窗口的显示位置 mSubLayer决定子窗口在同级的兄弟窗口的显示位置值越高显示约靠上
WindowState 产生了他自己这个窗口的layer值后在添加窗口的时候就会把所有窗口按layer排序插入mWindows列表中,在通过 adjustWallpaperWindowsLocked();进行层级调整
当客户端通过IWindowsessionadd后,客户端还没有获得Surface只有在执行IWindowsessionrelayout后客户端才获得了一块Surface IWindowsessionrelayout根据客户端提供的参数,为客户端提供surface具体实现是WMSrelayoutWindow
总的来说就是根据用户传入的参数,更新WindowState然后遍历所有窗口布局在设置合适的Surface尺寸,在返回给用户端
performLayoutAndPlaceSurfacesLocked 会循环调用6次里边的逻辑大概如下
这里主要下,因为之前加了锁requestTraversalLocked他又会重复执行performLayoutAndPlaceSurfacesLocked();因此会重复循环执行布局
布局这部分就记个原理吧
布局完成后客户端的尺寸和surface都得到了就可以绘制 了WMS会通知客户端布局发送变化
总结,WMS 负责管理所有的窗口包括系统窗口和APP窗口,而窗口必须有一个WindowToken所为标识符同时WMS为每个窗口创建一个WindowState类,这是窗口在服务端的抽象WindowState则绑定了一个客户端的IWindow类,WMS通过这个IWindow 向APP发送消息
AMS在启动Activity的时候把ActivityRecordtoken 通过wmsaddtoken 注册到WMS又把这个token发送到APP端因此三方可以通过这个token正确找到对应的数据
WMS负责给所以窗口按ZOrder排序,确定窗口的尺寸,提供绘画用的surface
Activity的窗口是先wmsaddtoken 建立windowToken关系 wmsaddWindow 添加串口, WMSrelayout获取surface 完成
一个windowToken对应一个Activity 但是可能对应多个windowSatate也就是对应多个窗口
是view树的根实现类是viewRootImpl但是他不是view他是用来和WMS进行交流的管理者viewRootImpl内部有个IWindowSession,是WMS提供的匿名binder,同时还有个iWindow子类,用来让WMS给viewr发消息 view通过ViewRoot向WMS发消息WMS在通过IWIndow 向APP发消息 每个View树只有一个ViewRoot,每个Activity也只有一个ViewRoot UI绘制,事件传递都是通过ViewRoot
实现类是PhoneWindow Activity和View的沟通就是通过WindowActivity实现window的各种回调一个Activity也对应一个PhoneWindow也对应一个View树
Docerview 就是View树的根这是一个View 他由PhoneWindow管理 下文的WindowManager也由phoneWindow管理
他还管理window的属性 WindowManagerlayoutparams
他是一个代理类他集成自ViewManager他的实现是WindowManagerImpl这是每个Activity都有一个但是他只是把工作委托给了 WindowManagerGlobal来实现 他负责添加删除窗口,更新窗口并控制窗口的补件属性WindowManagerLayoutparams
是进程唯一的负责这个进程的窗口管理他里边有三个集合保存这个进程所有窗口的数据这里的每个数据根据index得到的是同一个Activity属性所有的WindowManager的 *** 作都转到他这里来
private final ArrayList<View> mViews 每个view是个跟节点
private final ArrayList<ViewRootImpl> mRoots view对应的viewRoot
private final ArrayList<WindowManagerLayoutParams> mParams 窗口的layoutparams属性每个窗口一个
对于一个acitivity对象永远对应一个PhoneWindow,一个WindowManagerImpl,一个WMS端的APPWindowToken,一个AMS里的ActivityRecord(但是如果一个activity在栈里有多个对象,就有多个ActivityRecord和AppWindowToken),acitvity 的默认窗口的view树是DocerView
一个窗口 对应一个ViewRoot,一个View树一个WindowManagerLayoutParams,一IWindow(WMS回调app)一个WSM端的WindowSatate
但是一个Activity可以有多个窗口,因此对应WMS里可能有多个WindowSatate这些WindowState都对应一个AppWindowToken
一个Activity可能被加载多次因此在AMS中可能有多个ActivityRecord对应这个activit的多个对象
但是一个进程则对应一个WindowManagerGlobal一个ActivityThread(主线程)一个ApplicationThread(AMS调用app)一个iWindowSession(viewroot向WMS发消息)
这里的区别就是 app与AMS 的交互是以进程之间进行通信而App与WMS的交互则是以窗口作为通信基础
当Activity由AMS启动时ActivityThread 通过handleResumeActivity执行resume相关的 *** 作这个函数首先是执行activityresume, 此时activity 对应的view树已经建立完成(oncreate中建立,PhoneWindow也创建了)需要把activity的窗口添加到WMS中去管理
这里的wm是WindowManager是每个activity一个他内部会调用WindowManagerGlobaladdView
WindowManagerGlobaladdView
这里会为窗口创建ViewRootImpl 并把viewViewRootImplWindowMaLayoutParams都保存在WindowManagerGlobal中, 并通过ViewRootImpl向WMS添加窗口
如果这个窗口是子窗口(wparamstype >= WindowManagerLayoutParamsFIRST_SUB_WINDOW &&
wparamstype <= WindowManagerLayoutParamsLAST_SUB_WINDOW)
就把子窗口的token设为父窗口的token否则就是所属activity的token
在来个图
在这里我们看到我们通过mWindowManager = (WindowManager) mContextgetSystemService(ContextWINDOW_SERVICE); 拿到的并不是远程的WMS而是本地的WindowManagerImpl 他又把请求转发给WindowManagerGlobal ,而WindowManagerGlobal作为进程单实例又是吧请求转给对应窗口的ViewRootImplViewRootImpl通过WMS的IWindowSession 把数据发给WMS
ViewRootImpl用来沟通View和WMS并接受WMS的消息这是双向的binder通信作为整个空间树的根部,控件的测量,布局,绘制,输入时间的派发都由ViewRootImpl来触发
ViewRootImpl由WindowManagerGlobal创建,是在activityThreadhandleResumeActivity时,先执行activityresume在调用wmaddView 就会执行WindowManagerGlobaladdView里创建ViewRootImpl,此时是在ui线程中
ViewRootImpl里的mView属性host属性,就是view树
添加窗口时通过requestLayout();向ui线程发送消息最后回调到ViewRootImplperformTraversals他是整个ui控件树,measurelayoutdraw的集合
这里分为五个阶段
预测量阶段进行第一次测量,获得viewgetMeasuredWitdh/Height,此时是控件树期望的尺寸会执行View的onMeasure
布局阶段,根据预测量的结果,通过IWindowSessionrelayout向WMS请求调整窗口的尺寸这会使WMS对窗口重新布局,并把结果返回给ViewRootImpl
最终测量阶段, 预测量的结果是view树期望的结果WMS可能会进行调整,在这里WMS已经把结果通知了ViewRootImpl因此这里会窗口实际尺寸performTraversals进行布局view及子类的onMeasure会被回调
布局阶段 测量完成后获得空间的尺寸,布局要确定控件的位置,View及子类的onLayout会被回调
绘制阶段,使用WMS提供的surface进行绘制,View及子类的onDraw会被回调
通常我们看到的都是 先measure,在layout在draw 这里看到其实measure先得到期望值,在和WMS沟通WMS在调整后,返回确定值,在根据确定值进行mesure
measureHierarchy里会通过三次协商执行performMeasure 来确认合适的尺寸
performMeasure 会调用view 的measure 优会调用onMeasure 我们可重写onMeasure来实现测量而measure 方法是final的onMeasure 的结果通过setMeasuredDimension方法保存
对于view onMeasure比较容易 对于ViewGroup则还要遍历调用他所以子view的measure 并且需要考虑padding和子view 的margin padding是控件外内边距 margin 是控件外边距
ViewGroup需要先测量完子view在根据子view的测量值得到自己的宽高举例,如果只有一个子view那么ViewGroup的宽= 子view的宽+子view的margin+viewg的padding 至少是这个值
继续回到performTraversals
这里就是提前测量了一下得到控件树希望的尺寸大小,
通过relayoutWindow来布局窗口 ViewRootImpl 通过IWindowSession 来通知WMS进行窗口布局
这里主要下 调用WMS后WMS会调整窗口的尺寸 同时会生成surface返回给ViewRootImpl 因此后续的绘画就有了画布了可以看到最后的参数是mSurface这是本地的surface 这里会和wms的进行绑定
接下来继续performTraversals,绑定WMS返回的surface然后更新尺寸
最后进行最终测量 上边过程太乱了 了解下就行还是看常见的控件绘制流程
绘制由viewRootImplperformTraversals触发, 抽取出来后,就是这样
就是直接调用view树的根的measure方法 传入到View
该方法是final 意味着无法重写这里又会调用onMeasure
因此对于view在onMeasure中调整好高度,通过setMeasuredDimension设置好自己的测量宽高就可以了
对应ViewGroup则在onMeasure中,先要遍历子view调用他们的measure(注意一定是调用子类的measure,measure又会调用onMeasure), 子view宽高都知道后,在根据子view的宽高来设置自己也就是ViewGroup的宽高受子view影响
可以看到view的measure又调用了onMeasure, 如果是view 则可以直接重新onMeasure来设定大小而对于ViewGroup, 则需要重写onMeasure来先遍历子view设定大小然后再设定viewGroup的大小 ViewGroup并没有重写onMeasure因为每个ViewGroup要实现的效果不同,需要自己完成但ViewGroup提供了几个方法供ViewGroup的继承类来遍历子view
view的宽高由自己的layoutParams和父view提供的 widthMeasureSpec|heightMeasureSpec共同决定
View 自己的宽高,是保存在LayoutParams中对,以宽举例 LayoutParamswidth 有三种情况,精确值(就是指定大小),MATCH_PARENT WRAP_CONTENT,模式则有fuview提供有 unspecified,exactly,at_most三种
匹配如下
其实这个很好理解 如果子view自己指定了宽高就用他的值就可以如果子view是match_parent那就使用父view提供的宽高 如果子view是wrap_content,那就不能超过父view的值
看下ViewGroup为子view绘制而提供的方法,可以看到ViewGroup会减去padding和margin,来提供子view的宽高
上步measure过程未完成后,整个view书的 测量宽高都得到了也就是viewgetMeasuredWidth()和getMeasuredHeight()
performLayout中会调用mViewlayout 这样就把事件从ViewRootImpl传递到了view而layout中又会调用onLayoutViewGroup需要重写onLayout为子view进行布局,遍历调用子view的layout因此就完成整个view树的laylut过程
竖向的实现, 竖向的就行把view从上到下一次排开
这里注意区分measure过程是先得到子view的测量值,在设定父ViewGroup的值而layout过程则是先传入父view的左上右下值,来计算子view的左上右下的位置值这里应该具有普遍性但不知道是否绝对
performDraw 中的调用draw又调用mViewdraw然后就进入view树的绘制了
view的draw 又会调用onDraw ,viewGroup又调用dispatchDraw()把draw分发到子view里 绘制的画布就是canvas 这是从surfacelockCanvas中获得的一个区域
而在ViewGroupdispatchDraw中重要的一点是getChildDrawingOrder 表示子view的绘制顺序默认是与ziview的添加顺序一样我们也可以改变他最后绘制的会显示在最上边,而这也影响view的事件传递顺序
viewdraw 就是一层一层的画内容先画北京,在onDraw在画装饰什么的
canvastranslate(100,300)通过平移坐标系使之后的内容可以直接在新坐标系中绘制
这就是ViewGroup在向子view传递canvas的时候方便多了 会之前先对其ziview的左上角那么子view就可以直接从自己坐标轴的(0,0)开始绘制, 绘制完成后ViewGroup在还原原有坐标系
canvassave canvasrestore 用来保存还原坐标系
viewinvalidate
当某个view发送变化需要重绘时,通过viewinvalidate向上通知到ViewRootImpl从这个view到ViewRootImpl的节点都标记为藏区域dirty area ViewRootimpl再次从上到下重绘时,只绘制这些脏区域效率高
本来安卓兼容使用键盘,也支持,触摸二者的输入事件派发不一样使用键盘时会有个控件处于获得焦点状态处于触摸模式则由用户决定 因此控件分为两类任何情况下都能获得焦点如输入文本框只有在键盘 *** 作时才能获得焦点如菜单,按钮
安卓里有触摸模式当发送任意触摸时进入触摸模式当发送方向键和键盘或者执行ViewrequestRocusFromTouch时,退出触摸模式
获取焦点 viewrequest
先检查是否能获取焦点,
然后设置获取简单的标记,
向上传递到ViewRootimpl保证只能有一个控件获取焦点
通知焦点变化的监听者
更新view的drawable状态,
requestChildFocus会把焦点事件层层上报取消原来有焦点的控件最后的效果就是从viewrootimpl中到最终有焦点的view构成一条 mFoucued 标识的链条来个图就明白了每个view的mFocused总是指向他的直接下级
获取focus的传递是从底层view到顶层的ViewRootImpl而取消focus测试从顶层的ViewRootimpl到底层原来那个获得焦点的view
而如果是ViewGroup请求获取焦点,会根据FLAG_MASK_FOCUSABILITY特性来做不同方式,分别有先让自己获取焦点,或者安卓view的索引递增或者递减来匹配view
ViewRootImpl 中的WindowInputEventReceiver接受输入事件他会把事件包装成一个QueuedInputEvent然后追加到一个单链表的末尾接着重头到尾的处理输入事件,并通过deliverInputEvent完成分发这里会把单链表所有事件都处理完
deliverInput中又会把触摸事件执行到通过 ViewPreImeInputStageprocessKeyEvent 转入mViewdispatchPointerEvent(event)这里又进入 dispatchTouchEvent
MotionEvent是触摸事件的封装getAction可以拿到动作的类型和触控点索引号
getX(),getY()拿到动作的位置信息通过getPointID拿到触控点的id 动作以down 开头跟多个move最后是up
,当事件返回true表示事件被消费掉了
EditText是在获得焦点时d出软键盘,你可以在初始化activity的时候把焦点放在其他控件上,获得焦点可以在xml里面配置 android:getFocus="true";拼写可能不对,大意差不错,手上没有IDE
以上就是关于android中edittex焦点设置和d不d出输入法的问题全部的内容,包括:android中edittex焦点设置和d不d出输入法的问题、测试中帮助选项怎么测试、深入理解android2-WMS,控件等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)