AdapterKeyboardLayout.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.EventSystems;
  5. using UnityEngine.UI;
  6. [RequireComponent(typeof(RectTransform))]
  7. public class AdapterKeyboardLayout : UIBehaviour
  8. {
  9. /// <summary>
  10. /// 必须设置值,判断是由哪个InputField发起的
  11. /// </summary>
  12. public InputField m_InputField;
  13. /// <summary>
  14. /// 在适配虚拟键盘时,对齐的点, 默认为InputField
  15. /// </summary>
  16. public RectTransform anchorTransform;
  17. /// <summary>
  18. /// 在适配虚拟键盘时,做偏移的对象, , 默认为Self
  19. /// </summary>
  20. public RectTransform offsetTransform;
  21. private Canvas m_Canvas;
  22. private RectTransform m_OffsetParentTransform;
  23. private Vector3 m_AnchorPos;
  24. private Vector3 m_OffsetInitPos;
  25. private Vector2 m_OffsetScreePos = Vector2.zero;
  26. private bool m_LastVisible = false;
  27. private bool IsNeedGetHight = true;
  28. private int m_KeyboardHeight_int = 0;
  29. public Canvas canvas
  30. {
  31. get
  32. {
  33. if (this.m_Canvas == null)
  34. {
  35. this.CacheCanvas();
  36. }
  37. return this.m_Canvas;
  38. }
  39. }
  40. protected override void OnEnable()
  41. {
  42. base.OnEnable();
  43. if (!m_InputField)
  44. {
  45. enabled = false;
  46. Debug.LogError("InputField is Null", gameObject);
  47. return;
  48. }
  49. if (!anchorTransform) anchorTransform = (RectTransform)m_InputField.transform;
  50. if (!offsetTransform) offsetTransform = (RectTransform)transform;
  51. Transform parent = offsetTransform.parent;
  52. if (!parent)
  53. {
  54. enabled = false;
  55. Debug.LogError("offsetTransform's parent is Null", gameObject);
  56. return;
  57. }
  58. m_OffsetParentTransform = (RectTransform)parent;
  59. }
  60. protected override void OnTransformParentChanged()
  61. {
  62. base.OnTransformParentChanged();
  63. m_Canvas = null;
  64. }
  65. protected override void OnCanvasHierarchyChanged()
  66. {
  67. m_Canvas = null;
  68. }
  69. private void CacheCanvas()
  70. {
  71. List<Canvas> list = new List<Canvas>();
  72. base.gameObject.GetComponentsInParent(false, list);
  73. if (list.Count > 0)
  74. {
  75. int num = 0;
  76. while (num < list.Count)
  77. {
  78. if (!list[num].isActiveAndEnabled)
  79. {
  80. num++;
  81. continue;
  82. }
  83. m_Canvas = list[num];
  84. break;
  85. }
  86. }
  87. else
  88. {
  89. m_Canvas = null;
  90. }
  91. }
  92. private void Update()
  93. {
  94. Canvas curCanvas = canvas;
  95. if (curCanvas == null)
  96. {
  97. return;
  98. }
  99. if (!m_InputField.isFocused)
  100. {
  101. if (!Mathf.Approximately(m_OffsetScreePos.y, 0))
  102. {
  103. offsetTransform.localPosition = m_OffsetInitPos;
  104. m_OffsetScreePos.y = 0;
  105. DisposeMobileKeyboard();
  106. }
  107. if (!IsNeedGetHight)
  108. {
  109. SetIsNeedGetHight(true);
  110. Debug.Log("=========IsNeedGetHight===true======");
  111. }
  112. return;
  113. }
  114. bool visible = GetMobileKeyboardVisible();
  115. if (visible)
  116. {
  117. if (m_LastVisible != visible)
  118. {
  119. // 左下角
  120. Rect rect = anchorTransform.rect;
  121. m_AnchorPos = anchorTransform.TransformPoint(rect.min);
  122. m_AnchorPos = m_OffsetParentTransform.InverseTransformPoint(m_AnchorPos);
  123. m_OffsetInitPos = offsetTransform.localPosition;
  124. }
  125. float height = GetMobileKeyboardHeight();
  126. if (!Mathf.Approximately(height, m_OffsetScreePos.y))
  127. {
  128. m_OffsetScreePos.y = height;
  129. Vector2 pos;
  130. Camera camera = (curCanvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : curCanvas.worldCamera);
  131. if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_OffsetParentTransform, m_OffsetScreePos, camera, out pos))
  132. {
  133. if (m_AnchorPos.y < pos.y)
  134. {
  135. offsetTransform.localPosition = new Vector2(m_OffsetInitPos.x, m_OffsetInitPos.y + pos.y - m_AnchorPos.y);
  136. }
  137. else
  138. {
  139. offsetTransform.localPosition = m_OffsetInitPos;
  140. }
  141. }
  142. }
  143. }
  144. else
  145. {
  146. if (!Mathf.Approximately(m_OffsetScreePos.y, 0))
  147. {
  148. offsetTransform.localPosition = m_OffsetInitPos;
  149. m_OffsetScreePos.y = 0;
  150. DisposeMobileKeyboard();
  151. }
  152. }
  153. m_LastVisible = visible;
  154. }
  155. private bool GetMobileKeyboardVisible()
  156. {
  157. #if UNITY_EDITOR
  158. return true;
  159. #elif UNITY_ANDROID || UNITY_IOS
  160. return TouchScreenKeyboard.visible;
  161. #else
  162. return true;
  163. #endif
  164. }
  165. private float GetMobileKeyboardHeight()
  166. {
  167. #if UNITY_EDITOR
  168. return 0;
  169. #elif UNITY_ANDROID
  170. return AndroidGetKeyboardHeight_E();//GetMobileKeyboardHeight_Android();
  171. #elif UNITY_IOS
  172. return TouchScreenKeyboard.area.height;
  173. #else
  174. return 0;
  175. #endif
  176. }
  177. private void DisposeMobileKeyboard()
  178. {
  179. #if UNITY_ANDROID
  180. if (m_InputDialogAJO != null)
  181. {
  182. m_InputDialogAJO.Dispose();
  183. m_InputDialogAJO = null;
  184. }
  185. if (m_ViewAJO != null)
  186. {
  187. Debug.Log("释放 m_View AJO");
  188. m_ViewAJO.Dispose();
  189. m_ViewAJO = null;
  190. }
  191. if (m_RectAJO != null)
  192. {
  193. Debug.Log("释放 m_Rect AJO");
  194. m_RectAJO.Dispose();
  195. m_RectAJO = null;
  196. }
  197. if (m_PointAJO != null)
  198. {
  199. m_PointAJO.Dispose();
  200. m_PointAJO = null;
  201. }
  202. if (m_DefaultDisplayAJO != null)
  203. {
  204. m_DefaultDisplayAJO.Dispose();
  205. m_DefaultDisplayAJO = null;
  206. }
  207. #endif
  208. }
  209. #if UNITY_ANDROID
  210. private static float m_KeyboardHeight = 0;
  211. private static int m_CalcFrameCount = 0;
  212. private static AndroidJavaObject m_InputDialogAJO = null;
  213. private static AndroidJavaObject m_ViewAJO = null;
  214. private static AndroidJavaObject m_RectAJO = null;
  215. private static AndroidJavaObject m_PointAJO = null;
  216. private static AndroidJavaObject m_DefaultDisplayAJO = null;
  217. private static float GetMobileKeyboardHeight_Android()
  218. {
  219. // 同一帧内不重复计算
  220. if (Time.frameCount == m_CalcFrameCount) { return m_KeyboardHeight; }
  221. m_CalcFrameCount = Time.frameCount;
  222. if (m_InputDialogAJO == null || m_ViewAJO == null || m_DefaultDisplayAJO == null)
  223. {
  224. using (AndroidJavaClass unityPlayerAJC = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
  225. {
  226. using (AndroidJavaObject currentActivityAJO = unityPlayerAJC.GetStatic<AndroidJavaObject>("currentActivity"))
  227. {
  228. if (m_InputDialogAJO == null || m_ViewAJO == null)
  229. {
  230. using (AndroidJavaObject unityPlayerAJO = currentActivityAJO.Get<AndroidJavaObject>("mUnityPlayer"))
  231. {
  232. if (m_InputDialogAJO == null)
  233. {
  234. AndroidJavaClass dialogAJC = new AndroidJavaClass("android.app.Dialog");
  235. AndroidJavaObject[] fieldsAJO = unityPlayerAJO.Call<AndroidJavaObject>("getClass").Call<AndroidJavaObject[]>("getDeclaredFields");
  236. for (int i = 0, iMax = fieldsAJO.Length; i < iMax; i++)
  237. {
  238. AndroidJavaObject dialogAJO = fieldsAJO[i].Call<AndroidJavaObject>("get", unityPlayerAJO);
  239. if (dialogAJO == null)
  240. {
  241. continue;
  242. }
  243. if (AndroidJNI.IsInstanceOf(dialogAJO.GetRawObject(), dialogAJC.GetRawClass()))
  244. {
  245. m_InputDialogAJO = dialogAJO.Call<AndroidJavaObject>("getWindow")
  246. .Call<AndroidJavaObject>("getDecorView");
  247. break;
  248. }
  249. }
  250. }
  251. if (m_ViewAJO == null)
  252. {
  253. m_ViewAJO = unityPlayerAJO.Call<AndroidJavaObject>("getView");
  254. }
  255. }
  256. }
  257. if (m_DefaultDisplayAJO == null)
  258. {
  259. m_DefaultDisplayAJO = currentActivityAJO.Call<AndroidJavaObject>("getWindowManager").Call<AndroidJavaObject>("getDefaultDisplay");
  260. }
  261. }
  262. }
  263. }
  264. if (m_RectAJO == null)
  265. {
  266. m_RectAJO = new AndroidJavaObject("android.graphics.Rect");
  267. }
  268. if (m_PointAJO == null)
  269. {
  270. m_PointAJO = new AndroidJavaObject("android.graphics.Point");
  271. }
  272. float screenH = Screen.height;
  273. float realScreenH = 0;
  274. if (m_DefaultDisplayAJO != null)
  275. {
  276. m_DefaultDisplayAJO.Call("getRealSize", m_PointAJO);
  277. realScreenH = m_PointAJO.Get<int>("y");
  278. }
  279. else
  280. {
  281. realScreenH = screenH;
  282. }
  283. float height = 0f;
  284. if (m_InputDialogAJO != null)
  285. {
  286. bool result = m_InputDialogAJO.Call<bool>("getGlobalVisibleRect", m_RectAJO);
  287. if (result)
  288. {
  289. float inputDialogHeight = m_RectAJO.Call<int>("height");
  290. height += inputDialogHeight;
  291. }
  292. }
  293. if (m_ViewAJO != null)
  294. {
  295. m_ViewAJO.Call("getWindowVisibleDisplayFrame", m_RectAJO);
  296. float viewBottom = m_RectAJO.Get<int>("bottom");
  297. height += realScreenH - viewBottom;
  298. }
  299. m_KeyboardHeight = height * screenH / realScreenH;
  300. return m_KeyboardHeight;
  301. }
  302. public int AndroidGetKeyboardHeight()
  303. {
  304. using (AndroidJavaClass Unityclass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
  305. {
  306. AndroidJavaObject View = Unityclass.GetStatic<AndroidJavaObject>("currentActivity").
  307. Get<AndroidJavaObject>("mUnityPlayer").
  308. Call<AndroidJavaObject>("getView");
  309. using (AndroidJavaObject Rct = new AndroidJavaObject("android.graphics.Rect"))
  310. {
  311. View.Call("getWindowVisibleDisplayFrame", Rct);
  312. //Debug.Log(Screen.height - Rct.Call<int>("height"));
  313. return Screen.height - Rct.Call<int>("height");
  314. }
  315. }
  316. }
  317. public int AndroidGetKeyboardHeight_E()
  318. {
  319. if (Time.frameCount == m_CalcFrameCount || !IsNeedGetHight) { return m_KeyboardHeight_int; }
  320. m_CalcFrameCount = Time.frameCount;
  321. GetJavaClass();
  322. m_ViewAJO.Call("getWindowVisibleDisplayFrame", m_RectAJO);
  323. //Debug.Log(Screen.height - Rct.Call<int>("height"));
  324. int h = Screen.height - m_RectAJO.Call<int>("height");
  325. if (h == m_KeyboardHeight_int)
  326. {
  327. SetIsNeedGetHight(false);
  328. }
  329. m_KeyboardHeight_int = h;
  330. return m_KeyboardHeight_int;
  331. }
  332. private void GetJavaClass()
  333. {
  334. if (m_ViewAJO == null)
  335. {
  336. using (AndroidJavaClass Unityclass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
  337. {
  338. m_ViewAJO = Unityclass.GetStatic<AndroidJavaObject>("currentActivity").
  339. Get<AndroidJavaObject>("mUnityPlayer").
  340. Call<AndroidJavaObject>("getView");
  341. }
  342. Debug.Log("获取 m_View AJO");
  343. }
  344. if (m_RectAJO == null)
  345. {
  346. Debug.Log("获取 m_Rect AJO");
  347. m_RectAJO = new AndroidJavaObject("android.graphics.Rect");
  348. }
  349. }
  350. #endif
  351. private void SetIsNeedGetHight(bool value)
  352. {
  353. IsNeedGetHight = value;
  354. if (IsNeedGetHight)
  355. {
  356. m_KeyboardHeight_int = 0;
  357. }
  358. }
  359. }