{"id":470669,"date":"2025-08-14T03:03:17","date_gmt":"2025-08-14T03:03:17","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=470669"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=470669","title":{"rendered":"<span>TAO Bubbles: \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u044b\u0435 \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u044b\u0435 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u0434\u043b\u044f \u0432\u0430\u0448\u0438\u0445 Jetpack Compose \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"bordered full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/66b\/92c\/798\/66b92c798fb654a9c0eafd80be31860e.png\" width=\"640\" height=\"611\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/66b\/92c\/798\/66b92c798fb654a9c0eafd80be31860e.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/66b\/92c\/798\/66b92c798fb654a9c0eafd80be31860e.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 Android-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043d\u043e\u0432\u044b\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c \u0438\u043b\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0432 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043f\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443. \u0422\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0435 \u043e\u043a\u043d\u0430 \u0438\u043b\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0432\u044f\u0437\u0447\u0438\u0432\u044b\u043c\u0438. \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435 \u0435\u0441\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u043e \u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b UI \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u0443\u044e \u043f\u043e\u043c\u043e\u0449\u044c. \u0412\u0441\u0442\u0440\u0435\u0447\u0430\u0439\u0442\u0435 <strong>TAO Bubbles<\/strong> \u2013 \u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f <strong>Jetpack Compose<\/strong>, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u044b\u0445 &#171;<strong>\u043f\u0443\u0437\u044b\u0440\u0435\u0439<\/strong>&#171;, &#171;<strong>\u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a<\/strong>&#187; \u0438\u043b\u0438 &#171;<strong>\u0442\u0443\u043b\u0442\u0438\u043f\u043e\u0432<\/strong>&#171;, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 UI-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b.<strong>TAO Bubbles<\/strong> \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u044b\u0445 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432, \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043d\u043e\u0432\u044b\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0438\u043b\u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0439 \u0441\u043f\u0440\u0430\u0432\u043a\u0438 \u043f\u0440\u044f\u043c\u043e \u0432 \u0432\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<p><em>P.S. \u041f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f Jetpack Compose, \u0442\u0430\u043a \u0447\u0442\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u043a\u0440\u0438\u0442\u0438\u043a\u0430 \u0438 pull requests \u0441 \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442\u0441\u044f ).<\/em><\/p>\n<p><strong>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 TAO Bubbles \u0434\u043b\u044f Jetpack Compose<\/strong><\/p>\n<ul>\n<li>\n<p><strong>\u041f\u043e\u043b\u043d\u0430\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0432\u0438\u0434\u0430<\/strong>: \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0439\u0442\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0441\u0442\u0440\u0435\u043b\u043a\u0438, \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c, \u0440\u0430\u0434\u0438\u0443\u0441\u043e\u043c \u0443\u0433\u043b\u043e\u0432, \u0446\u0432\u0435\u0442\u0430\u043c\u0438, \u0433\u0440\u0430\u043d\u0438\u0446\u0430\u043c\u0438 \u0438 \u043c\u043d\u043e\u0433\u0438\u043c \u0434\u0440\u0443\u0433\u0438\u043c. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043b\u0435\u0433\u043a\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0438\u043b\u044c \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u043f\u043e\u0434 \u0434\u0438\u0437\u0430\u0439\u043d \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412\u043d\u0443\u0442\u0440\u0438 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u0432\u0430\u0448 \u043c\u0430\u043a\u0435\u0442 Composable.<\/p>\n<\/li>\n<li>\n<p><strong>\u0413\u0438\u0431\u043a\u043e\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/strong>: \u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u0446\u0435\u043b\u0435\u0432\u043e\u0433\u043e composable-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 (<strong>LEFT<\/strong>, <strong>RIGHT<\/strong>, <strong>TOP<\/strong>, <strong>BOTTOM<\/strong>).<\/p>\n<\/li>\n<li>\n<p><strong>\u0410\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u044f \u043a \u0433\u0440\u0430\u043d\u0438\u0446\u0430\u043c \u044d\u043a\u0440\u0430\u043d\u0430<\/strong>: \u043f\u0443\u0437\u044b\u0440\u0438 <strong><em>Bubble<\/em><\/strong> \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u0443\u044e\u0442 \u0441\u0432\u043e\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u044d\u043a\u0440\u0430\u043d\u0430, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043e\u043f\u044b\u0442 \u043d\u0430 \u043b\u044e\u0431\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445.<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u043a\u0430\u0437<\/strong>: \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 <strong><em>BubbleShowController<\/em> <\/strong>\u0434\u043b\u044f \u043b\u0435\u0433\u043a\u043e\u0433\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0438\u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u043e\u0434\u043d\u0430 \u0437\u0430 \u0434\u0440\u0443\u0433\u043e\u0439, \u043f\u0440\u043e\u0432\u043e\u0434\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0448\u0430\u0433\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p><strong>\u0410\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f\/\u0438\u0441\u0447\u0435\u0437\u043d\u043e\u0432\u0435\u043d\u0438\u044f<\/strong>: \u041f\u043b\u0430\u0432\u043d\u044b\u0435 \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u044b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u0438\u0441\u0447\u0435\u0437\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u0434\u0435\u043b\u0430\u044e\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0431\u043e\u043b\u0435\u0435 \u0436\u0438\u0432\u044b\u043c.<\/p>\n<\/li>\n<li>\n<p><strong>\u0417\u0430\u0442\u0435\u043c\u043d\u0435\u043d\u0438\u0435 \u0444\u043e\u043d\u0430 (Scrim)<\/strong>: \u041e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u0437\u0430\u0442\u0435\u043c\u043d\u0435\u043d\u0438\u044f \u0444\u043e\u043d\u0430 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u0441\u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0430 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>\u0414\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 API<\/strong>: \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u0430 \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0430\u043a\u0442\u0438\u043a Jetpack Compose, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0438 \u0438\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0439 API.<\/p>\n<\/li>\n<li>\n<p><strong>\u041b\u0435\u0433\u043a\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435<\/strong>: \u041d\u0438\u043a\u0430\u043a\u0438\u0445 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439. \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0443 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0435.<\/p>\n<\/li>\n<\/ul>\n<figure class=\"bordered\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/35f\/7a1\/bdb\/35f7a1bdbf4f9fc3cf50dae00f5bdce3.gif\" width=\"400\" height=\"900\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/35f\/7a1\/bdb\/35f7a1bdbf4f9fc3cf50dae00f5bdce3.gif 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/35f\/7a1\/bdb\/35f7a1bdbf4f9fc3cf50dae00f5bdce3.gif 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p><strong>\u041a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442?<\/strong><\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f (<strong>\u043e\u0434\u0438\u043d\u043e\u0447\u043d\u044b\u0439<\/strong> <strong>Bubble<\/strong>):<\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0435 \u043e\u0431\u0449\u0438\u0435 \u0441\u0442\u0438\u043b\u0438 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0432\u0430\u0448\u0438\u0445 &#171;\u043f\u0443\u0437\u044b\u0440\u0435\u0439&#187; \u0438\u043b\u0438 \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u044b.<\/p>\n<pre><code class=\"kotlin\">    val settings = BubblesSettings(             scrimColor = Color(0x22002EFF), \/\/ \u0426\u0432\u0435\u0442 \u0437\u0430\u0442\u0435\u043c\u043d\u0435\u043d\u0438\u044f \u0444\u043e\u043d\u0430             backgroundColor = OrangeVeryLight, \/\/ \u0426\u0432\u0435\u0442 \u0444\u043e\u043d\u0430 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438             bubbleBorderColor = Color.Black, \/\/ \u0426\u0432\u0435\u0442 \u0440\u0430\u043c\u043a\u0438             bubbleBorderWidth = 2.dp \/\/ \u0422\u043e\u043b\u0449\u0438\u043d\u0430 \u0440\u0430\u043c\u043a\u0438             ... \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435         )<\/code><\/pre>\n<p>\u041f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438.<\/p>\n<pre><code class=\"kotlin\">    val bubbleData = BubbleData(         id = \"Intro_Feature\", \/\/ \u0423\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 ID \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (\u043f\u043e\u043a\u0430\u0437\u0430\u043d\u0430\/\u0441\u043a\u0440\u044b\u0442\u0430)         arrowPosition = ArrowPosition.BOTTOM, \/\/ \u0421 \u043a\u0430\u043a\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u0446\u0435\u043b\u0435\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043f\u0440\u0438\u043b\u0435\u0433\u0430\u0435\u0442 \u0441\u0442\u0440\u0435\u043b\u043a\u0430 \u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430         content = { onDismissClick, onStopShowRequest -&gt;             \/\/ \u0417\u0434\u0435\u0441\u044c \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f \u043b\u044e\u0431\u043e\u0439 \u0432\u0430\u0448 Composable-\u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438             \/\/ onDismissClick - \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u0430\u044f \u043f\u043e \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u044e \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438             \/\/ onStopShowRequest - \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432\u0441\u0435\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 (\u0435\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f BubbleShowController)             Text(\"\u042d\u0442\u043e \u0432\u0430\u0436\u043d\u0430\u044f \u043d\u043e\u0432\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430!\")         }     )<\/code><\/pre>\n<p>\u0418 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0441\u0432\u043e\u0435\u043c \u043a\u043e\u0434\u0435:<\/p>\n<pre><code class=\"kotlin\">    @Composable     fun SingleBubbleExample() {         var showBubble by remember { mutableStateOf(true) }         var targetRect by remember { mutableStateOf&lt;Rect?&gt;(null) } \/\/ Rect \u0446\u0435\u043b\u0435\u0432\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430          Box(modifier = Modifier.fillMaxSize()) {             Button(                 onClick = { showBubble = !showBubble },                 modifier = Modifier                     .align(Alignment.Center)                     .onGloballyPositioned { coordinates -&gt;                         \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u0430 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430                         targetRect = coordinates.boundsInWindow()                     }             ) {                 Text(\"\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0443\")             }              Bubble(                 targetComponentRect = targetRect, \/\/ \u041f\u0435\u0440\u0435\u0434\u0430\u0435\u043c Rect \u0446\u0435\u043b\u0438                 bubbleData = bubbleData,          \/\/ \u041d\u0430\u0448\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438                 settings = settings,              \/\/ \u041d\u0430\u0448\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u0442\u0438\u043b\u044f                 isVisible = showBubble,           \/\/ \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c\u044e                 onDismissRequest = { showBubble = false } \/\/ \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u0438 \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0438             )                    }     }     <\/code><\/pre>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u043a\u0430\u0437\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a.<\/strong><br \/>\u041f\u043e\u043a\u0430\u0437 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u043d\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <strong><em>BubbleShowController<\/em><\/strong>.<\/p>\n<p>\u041f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a (\u0438\u043b\u0438 \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443) <strong><em>BubbleData <\/em><\/strong><em>\u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438<\/em>:<\/p>\n<pre><code class=\"kotlin\">    val testBubbles = listOf(         BubbleData(             id = \"Step_1\",             arrowPosition = ArrowPosition.BOTTOM,             content = { onDismissClick, onStopShowRequest -&gt;                 MyContent(\"\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430 1: \u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u0437\u0434\u0435\u0441\u044c\", onDismissClick, onStopShowRequest)             }         ),         BubbleData(             id = \"Step_2\",             arrowPosition = ArrowPosition.LEFT,             content = { onDismissClick, onStopShowRequest -&gt;                 MyContent(\"\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430 2: \u0417\u0430\u0442\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u044d\u0442\u043e\", onDismissClick, onStopShowRequest)             }         ),         BubbleData(             id = \"Step_3\",             arrowPosition = ArrowPosition.RIGHT,             content = { onDismissClick, onStopShowRequest -&gt;                 MyContent(\"\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430 3: \u0418 \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u0441\u044e\u0434\u0430!\", onDismissClick, onStopShowRequest)             }         )     )      \/\/ MyContent - \u0432\u0430\u0448 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 Composable \u0434\u043b\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438     @Composable     fun MyContent(text: String, onDismiss: () -&gt; Unit, onStopShow: () -&gt; Unit) {         Column(horizontalAlignment = Alignment.CenterHorizontally) {             Text(text)             Button(onClick = onDismiss) { Text(\"\u0414\u0430\u043b\u0435\u0435\") }             \/\/ Button(onClick = onStopShow) { Text(\"\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0442\u0443\u0440\") } \/\/ \u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e         }     }     <\/code><\/pre>\n<p>\u0418 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u044f \u043a\u0430\u0436\u0434\u044b\u0439 <strong><em>BubbleData <\/em><\/strong>\u0441 \u0446\u0435\u043b\u0435\u0432\u044b\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c :<\/p>\n<pre><code class=\"kotlin\">    @Composable     fun BubbleSequenceExample() {         \/\/ \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043f\u043e\u043a\u0430\u0437\u0430         val bubblesSettings = remember { testSettings } \/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438         val bubblesData = remember { testBubbles } \/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438. \u041d\u043e \u043c\u043e\u0436\u043d\u043e \u0438 \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443.          val bubbleShowController = rememberBubbleShowController( \/\/ \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043f\u043e\u043a\u0430\u0437\u0430              settings = bubblesSettings,             bubbles = bubblesData,             onFinished = {                 \/\/ \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a                 Log.d(\"BubbleShow\", \"\u0412\u0441\u0435 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u044b!\")             }         )          Box(             modifier = Modifier                 .fillMaxSize()                 .background(Color(0xFFE0F7FA))         ) {             \/\/ \u0412\u0430\u0448\u0438 UI \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u044b \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438             Box(                 modifier = Modifier                     .align(Alignment.TopStart)                     .padding(16.dp)                     .size(100.dp)                     \/\/ \u0421\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440                     .assignBubble(controller = bubbleShowController, bubbleData = bubblesData[0]),                 contentAlignment = Alignment.Center             ) {                 Text(\"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 1\", color = Color.Black)             }              Box(                 modifier = Modifier                     .align(Alignment.TopEnd)                     .padding(16.dp)                     .size(100.dp)                     .assignBubble(controller = bubbleShowController, bubbleData = bubblesData[1]),                 contentAlignment = Alignment.Center             ) {                 Text(\"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 2\", color = Color.Black)             }              Box(                 modifier = Modifier                     .align(Alignment.BottomStart)                     .padding(16.dp)                     .size(100.dp)                     .assignBubble(controller = bubbleShowController, bubbleData = bubblesData[2]),                 contentAlignment = Alignment.Center             ) {                 Text(\"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 3\", color = Color.Black)             }              \/\/ \u041a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u043e\u043a\u0430\u0437\u0430             Button(                 modifier = Modifier                     .align(Alignment.Center)                     .padding(top = 224.dp),                 onClick = {                     bubbleShowController.restartShow()                 }) {                 Text(\"\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u043e\u043a\u0430\u0437\")             }              \/\/ \u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0443 \u0438\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430             \/\/ Composable Bubble \u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438.             bubbleShowController.ShowBubbles()         }     }     <\/code><\/pre>\n<p>\u041c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 <strong><em>.assignBubble()<\/em><\/strong> \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0432\u0430\u0448\u0438 UI-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0441 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435. \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0437\u0430\u0442\u0435\u043c \u0441\u0430\u043c \u043f\u043e\u0437\u0430\u0431\u043e\u0442\u0438\u0442\u0441\u044f \u043e\u0431 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0438 <strong><em>targetComponentRect <\/em><\/strong>\u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438.<\/p>\n<p><strong>\u041d\u0443\u0436\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a?<\/strong><\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u0435\u0442\u0435 \u0438\u043c\u0435\u0442\u044c \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0438 \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044e \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u0443\u0437\u044b\u0440\u044f \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u0434\u043b\u044f \u043f\u043e\u043a\u0430\u0437\u0430, \u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 <strong><em>BubbleShowControllerExtended <\/em><\/strong>\u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0438 <strong><em>BubbleDataExtended <\/em><\/strong>\u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u0443\u0437\u044b\u0440\u044f.<\/p>\n<p><strong>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/strong><\/p>\n<p><strong>TAO Bubbles <\/strong>\u0434\u043b\u044f Jetpack Compose \u2013 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439, \u043d\u043e \u043c\u043e\u0449\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u0438 \u0442\u0443\u0440\u043e\u0432 \u043f\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0433\u0438\u0431\u043a\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0438 \u0443\u0434\u043e\u0431\u043d\u043e\u043c\u0443 API, \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043e\u043f\u044b\u0442, \u043f\u043e\u043c\u043e\u0433\u0430\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u043e\u0441\u0432\u0430\u0438\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043b\u0435\u0433\u043a\u043e \u0438 \u043d\u0435\u043f\u0440\u0438\u043d\u0443\u0436\u0434\u0435\u043d\u043d\u043e. <br \/>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 <strong>TAO Bubbles<\/strong> \u0432 \u0441\u0432\u043e\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435!<\/p>\n<p><strong>\u0421\u043a\u0430\u0447\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0440\u0435\u043b\u0438\u0437 \u0438 \u043a\u043e\u0434 \u0434\u0435\u043c\u043e-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/strong> <a href=\"https:\/\/github.com\/lordtao\/android-tao-bubbles\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/lordtao\/android-tao-bubbles<\/a><\/p>\n<p>\u041b\u0438\u0446\u0435\u043d\u0437\u0438\u044f MIT<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/936122\/\"> https:\/\/habr.com\/ru\/articles\/936122\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"bordered full-width\"><\/figure>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 Android-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043d\u043e\u0432\u044b\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c \u0438\u043b\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0432 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043f\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443. \u0422\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0435 \u043e\u043a\u043d\u0430 \u0438\u043b\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0432\u044f\u0437\u0447\u0438\u0432\u044b\u043c\u0438. \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435 \u0435\u0441\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u043e \u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b UI \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u0443\u044e \u043f\u043e\u043c\u043e\u0449\u044c. \u0412\u0441\u0442\u0440\u0435\u0447\u0430\u0439\u0442\u0435 <strong>TAO Bubbles<\/strong> \u2013 \u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f <strong>Jetpack Compose<\/strong>, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u044b\u0445 &#171;<strong>\u043f\u0443\u0437\u044b\u0440\u0435\u0439<\/strong>&#171;, &#171;<strong>\u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a<\/strong>&#187; \u0438\u043b\u0438 &#171;<strong>\u0442\u0443\u043b\u0442\u0438\u043f\u043e\u0432<\/strong>&#171;, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 UI-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b.<strong>TAO Bubbles<\/strong> \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u044b\u0445 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432, \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043d\u043e\u0432\u044b\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0438\u043b\u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0439 \u0441\u043f\u0440\u0430\u0432\u043a\u0438 \u043f\u0440\u044f\u043c\u043e \u0432 \u0432\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<p><em>P.S. \u041f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f Jetpack Compose, \u0442\u0430\u043a \u0447\u0442\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u043a\u0440\u0438\u0442\u0438\u043a\u0430 \u0438 pull requests \u0441 \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442\u0441\u044f ).<\/em><\/p>\n<p><strong>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 TAO Bubbles \u0434\u043b\u044f Jetpack Compose<\/strong><\/p>\n<ul>\n<li>\n<p><strong>\u041f\u043e\u043b\u043d\u0430\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0432\u0438\u0434\u0430<\/strong>: \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0439\u0442\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0441\u0442\u0440\u0435\u043b\u043a\u0438, \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c, \u0440\u0430\u0434\u0438\u0443\u0441\u043e\u043c \u0443\u0433\u043b\u043e\u0432, \u0446\u0432\u0435\u0442\u0430\u043c\u0438, \u0433\u0440\u0430\u043d\u0438\u0446\u0430\u043c\u0438 \u0438 \u043c\u043d\u043e\u0433\u0438\u043c \u0434\u0440\u0443\u0433\u0438\u043c. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043b\u0435\u0433\u043a\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0438\u043b\u044c \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u043f\u043e\u0434 \u0434\u0438\u0437\u0430\u0439\u043d \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412\u043d\u0443\u0442\u0440\u0438 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u0432\u0430\u0448 \u043c\u0430\u043a\u0435\u0442 Composable.<\/p>\n<\/li>\n<li>\n<p><strong>\u0413\u0438\u0431\u043a\u043e\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/strong>: \u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u0446\u0435\u043b\u0435\u0432\u043e\u0433\u043e composable-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 (<strong>LEFT<\/strong>, <strong>RIGHT<\/strong>, <strong>TOP<\/strong>, <strong>BOTTOM<\/strong>).<\/p>\n<\/li>\n<li>\n<p><strong>\u0410\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u044f \u043a \u0433\u0440\u0430\u043d\u0438\u0446\u0430\u043c \u044d\u043a\u0440\u0430\u043d\u0430<\/strong>: \u043f\u0443\u0437\u044b\u0440\u0438 <strong><em>Bubble<\/em><\/strong> \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u0443\u044e\u0442 \u0441\u0432\u043e\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u044d\u043a\u0440\u0430\u043d\u0430, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043e\u043f\u044b\u0442 \u043d\u0430 \u043b\u044e\u0431\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445.<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u043a\u0430\u0437<\/strong>: \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 <strong><em>BubbleShowController<\/em> <\/strong>\u0434\u043b\u044f \u043b\u0435\u0433\u043a\u043e\u0433\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0438\u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u043e\u0434\u043d\u0430 \u0437\u0430 \u0434\u0440\u0443\u0433\u043e\u0439, \u043f\u0440\u043e\u0432\u043e\u0434\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0448\u0430\u0433\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p><strong>\u0410\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f\/\u0438\u0441\u0447\u0435\u0437\u043d\u043e\u0432\u0435\u043d\u0438\u044f<\/strong>: \u041f\u043b\u0430\u0432\u043d\u044b\u0435 \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u044b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u0438\u0441\u0447\u0435\u0437\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u0434\u0435\u043b\u0430\u044e\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0431\u043e\u043b\u0435\u0435 \u0436\u0438\u0432\u044b\u043c.<\/p>\n<\/li>\n<li>\n<p><strong>\u0417\u0430\u0442\u0435\u043c\u043d\u0435\u043d\u0438\u0435 \u0444\u043e\u043d\u0430 (Scrim)<\/strong>: \u041e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u0437\u0430\u0442\u0435\u043c\u043d\u0435\u043d\u0438\u044f \u0444\u043e\u043d\u0430 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u0441\u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0430 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>\u0414\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 API<\/strong>: \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u0430 \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0430\u043a\u0442\u0438\u043a Jetpack Compose, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0438 \u0438\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0439 API.<\/p>\n<\/li>\n<li>\n<p><strong>\u041b\u0435\u0433\u043a\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435<\/strong>: \u041d\u0438\u043a\u0430\u043a\u0438\u0445 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439. \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0443 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0435.<\/p>\n<\/li>\n<\/ul>\n<figure class=\"bordered\"><\/figure>\n<p><strong>\u041a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442?<\/strong><\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f (<strong>\u043e\u0434\u0438\u043d\u043e\u0447\u043d\u044b\u0439<\/strong> <strong>Bubble<\/strong>):<\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0435 \u043e\u0431\u0449\u0438\u0435 \u0441\u0442\u0438\u043b\u0438 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0432\u0430\u0448\u0438\u0445 &#171;\u043f\u0443\u0437\u044b\u0440\u0435\u0439&#187; \u0438\u043b\u0438 \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u044b.<\/p>\n<pre><code class=\"kotlin\">    val settings = BubblesSettings(             scrimColor = Color(0x22002EFF), \/\/ \u0426\u0432\u0435\u0442 \u0437\u0430\u0442\u0435\u043c\u043d\u0435\u043d\u0438\u044f \u0444\u043e\u043d\u0430             backgroundColor = OrangeVeryLight, \/\/ \u0426\u0432\u0435\u0442 \u0444\u043e\u043d\u0430 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438             bubbleBorderColor = Color.Black, \/\/ \u0426\u0432\u0435\u0442 \u0440\u0430\u043c\u043a\u0438             bubbleBorderWidth = 2.dp \/\/ \u0422\u043e\u043b\u0449\u0438\u043d\u0430 \u0440\u0430\u043c\u043a\u0438             ... \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435         )<\/code><\/pre>\n<p>\u041f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438.<\/p>\n<pre><code class=\"kotlin\">    val bubbleData = BubbleData(         id = \"Intro_Feature\", \/\/ \u0423\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 ID \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (\u043f\u043e\u043a\u0430\u0437\u0430\u043d\u0430\/\u0441\u043a\u0440\u044b\u0442\u0430)         arrowPosition = ArrowPosition.BOTTOM, \/\/ \u0421 \u043a\u0430\u043a\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u0446\u0435\u043b\u0435\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043f\u0440\u0438\u043b\u0435\u0433\u0430\u0435\u0442 \u0441\u0442\u0440\u0435\u043b\u043a\u0430 \u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430         content = { onDismissClick, onStopShowRequest -&gt;             \/\/ \u0417\u0434\u0435\u0441\u044c \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f \u043b\u044e\u0431\u043e\u0439 \u0432\u0430\u0448 Composable-\u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438             \/\/ onDismissClick - \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u0430\u044f \u043f\u043e \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u044e \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438             \/\/ onStopShowRequest - \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432\u0441\u0435\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 (\u0435\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f BubbleShowController)             Text(\"\u042d\u0442\u043e \u0432\u0430\u0436\u043d\u0430\u044f \u043d\u043e\u0432\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430!\")         }     )<\/code><\/pre>\n<p>\u0418 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0441\u0432\u043e\u0435\u043c \u043a\u043e\u0434\u0435:<\/p>\n<pre><code class=\"kotlin\">    @Composable     fun SingleBubbleExample() {         var showBubble by remember { mutableStateOf(true) }         var targetRect by remember { mutableStateOf&lt;Rect?&gt;(null) } \/\/ Rect \u0446\u0435\u043b\u0435\u0432\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430          Box(modifier = Modifier.fillMaxSize()) {             Button(                 onClick = { showBubble = !showBubble },                 modifier = Modifier                     .align(Alignment.Center)                     .onGloballyPositioned { coordinates -&gt;                         \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u044e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u0430 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430                         targetRect = coordinates.boundsInWindow()                     }             ) {                 Text(\"\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0443\")             }              Bubble(                 targetComponentRect = targetRect, \/\/ \u041f\u0435\u0440\u0435\u0434\u0430\u0435\u043c Rect \u0446\u0435\u043b\u0438                 bubbleData = bubbleData,          \/\/ \u041d\u0430\u0448\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438                 settings = settings,              \/\/ \u041d\u0430\u0448\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u0442\u0438\u043b\u044f                 isVisible = showBubble,           \/\/ \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c\u044e                 onDismissRequest = { showBubble = false } \/\/ \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u0438 \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0438             )                    }     }     <\/code><\/pre>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u043a\u0430\u0437\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a.<\/strong><br \/>\u041f\u043e\u043a\u0430\u0437 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u043d\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <strong><em>BubbleShowController<\/em><\/strong>.<\/p>\n<p>\u041f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a (\u0438\u043b\u0438 \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443) <strong><em>BubbleData <\/em><\/strong><em>\u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438<\/em>:<\/p>\n<pre><code class=\"kotlin\">    val testBubbles = listOf(         BubbleData(             id = \"Step_1\",             arrowPosition = ArrowPosition.BOTTOM,             content = { onDismissClick, onStopShowRequest -&gt;                 MyContent(\"\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430 1: \u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u0437\u0434\u0435\u0441\u044c\", onDismissClick, onStopShowRequest)             }         ),         BubbleData(             id = \"Step_2\",             arrowPosition = ArrowPosition.LEFT,             content = { onDismissClick, onStopShowRequest -&gt;                 MyContent(\"\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430 2: \u0417\u0430\u0442\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u044d\u0442\u043e\", onDismissClick, onStopShowRequest)             }         ),         BubbleData(             id = \"Step_3\",             arrowPosition = ArrowPosition.RIGHT,             content = { onDismissClick, onStopShowRequest -&gt;                 MyContent(\"\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430 3: \u0418 \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u0441\u044e\u0434\u0430!\", onDismissClick, onStopShowRequest)             }         )     )      \/\/ MyContent - \u0432\u0430\u0448 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 Composable \u0434\u043b\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438     @Composable     fun MyContent(text: String, onDismiss: () -&gt; Unit, onStopShow: () -&gt; Unit) {         Column(horizontalAlignment = Alignment.CenterHorizontally) {             Text(text)             Button(onClick = onDismiss) { Text(\"\u0414\u0430\u043b\u0435\u0435\") }             \/\/ Button(onClick = onStopShow) { Text(\"\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0442\u0443\u0440\") } \/\/ \u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e         }     }     <\/code><\/pre>\n<p>\u0418 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u044f \u043a\u0430\u0436\u0434\u044b\u0439 <strong><em>BubbleData <\/em><\/strong>\u0441 \u0446\u0435\u043b\u0435\u0432\u044b\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c :<\/p>\n<pre><code class=\"kotlin\">    @Composable     fun BubbleSequenceExample() {         \/\/ \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043f\u043e\u043a\u0430\u0437\u0430         val bubblesSettings = remember { testSettings } \/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438         val bubblesData = remember { testBubbles } \/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438. \u041d\u043e \u043c\u043e\u0436\u043d\u043e \u0438 \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443.          val bubbleShowController = rememberBubbleShowController( \/\/ \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043f\u043e\u043a\u0430\u0437\u0430              settings = bubblesSettings,             bubbles = bubblesData,             onFinished = {                 \/\/ \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a                 Log.d(\"BubbleShow\", \"\u0412\u0441\u0435 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u044b!\")             }         )          Box(             modifier = Modifier                 .fillMaxSize()                 .background(Color(0xFFE0F7FA))         ) {             \/\/ \u0412\u0430\u0448\u0438 UI \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u044b \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438             Box(                 modifier = Modifier                     .align(Alignment.TopStart)                     .padding(16.dp)                     .size(100.dp)                     \/\/ \u0421\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440                     .assignBubble(controller = bubbleShowController, bubbleData = bubblesData[0]),                 contentAlignment = Alignment.Center             ) {                 Text(\"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 1\", color = Color.Black)             }              Box(                 modifier = Modifier                     .align(Alignment.TopEnd)                     .padding(16.dp)                     .size(100.dp)                     .assignBubble(controller = bubbleShowController, bubbleData = bubblesData[1]),                 contentAlignment = Alignment.Center             ) {                 Text(\"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 2\", color = Color.Black)             }              Box(                 modifier = Modifier                     .align(Alignment.BottomStart)                     .padding(16.dp)                     .size(100.dp)                     .assignBubble(controller = bubbleShowController, bubbleData = bubblesData[2]),                 contentAlignment = Alignment.Center             ) {                 Text(\"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 3\", color = Color.Black)             }              \/\/ \u041a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u043e\u043a\u0430\u0437\u0430             Button(                 modifier = Modifier                     .align(Alignment.Center)                     .padding(top = 224.dp),                 onClick = {                     bubbleShowController.restartShow()                 }) {                 Text(\"\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u043e\u043a\u0430\u0437\")             }              \/\/ \u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0443 \u0438\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430             \/\/ Composable Bubble \u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438.             bubbleShowController.ShowBubbles()         }     }     <\/code><\/pre>\n<p>\u041c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 <strong><em>.assignBubble()<\/em><\/strong> \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0432\u0430\u0448\u0438 UI-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0441 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435. \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0437\u0430\u0442\u0435\u043c \u0441\u0430\u043c \u043f\u043e\u0437\u0430\u0431\u043e\u0442\u0438\u0442\u0441\u044f \u043e\u0431 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0438 <strong><em>targetComponentRect <\/em><\/strong>\u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438.<\/p>\n<p><strong>\u041d\u0443\u0436\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a?<\/strong><\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u0435\u0442\u0435 \u0438\u043c\u0435\u0442\u044c \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0438 \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044e \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u0443\u0437\u044b\u0440\u044f \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u0434\u043b\u044f \u043f\u043e\u043a\u0430\u0437\u0430, \u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 <strong><em>BubbleShowControllerExtended <\/em><\/strong>\u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0438 <strong><em>BubbleDataExtended <\/em><\/strong>\u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u0443\u0437\u044b\u0440\u044f.<\/p>\n<p><strong>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/strong><\/p>\n<p><strong>TAO Bubbles <\/strong>\u0434\u043b\u044f Jetpack Compose \u2013 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439, \u043d\u043e \u043c\u043e\u0449\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u0438 \u0442\u0443\u0440\u043e\u0432 \u043f\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0433\u0438\u0431\u043a\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0438 \u0443\u0434\u043e\u0431\u043d\u043e\u043c\u0443 API, \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043e\u043f\u044b\u0442, \u043f\u043e\u043c\u043e\u0433\u0430\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u043e\u0441\u0432\u0430\u0438\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043b\u0435\u0433\u043a\u043e \u0438 \u043d\u0435\u043f\u0440\u0438\u043d\u0443\u0436\u0434\u0435\u043d\u043d\u043e. <br \/>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 <strong>TAO Bubbles<\/strong> \u0432 \u0441\u0432\u043e\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435!<\/p>\n<p><strong>\u0421\u043a\u0430\u0447\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0440\u0435\u043b\u0438\u0437 \u0438 \u043a\u043e\u0434 \u0434\u0435\u043c\u043e-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/strong> <a href=\"https:\/\/github.com\/lordtao\/android-tao-bubbles\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/lordtao\/android-tao-bubbles<\/a><\/p>\n<p>\u041b\u0438\u0446\u0435\u043d\u0437\u0438\u044f MIT<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/936122\/\"> https:\/\/habr.com\/ru\/articles\/936122\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-470669","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/470669","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=470669"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/470669\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=470669"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=470669"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=470669"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}