diff --git a/README.OPENSOURCE b/README.OPENSOURCE index 1a224340d1ccd524f747ab8aa48052e779be2446..c390449bf510ea00d59b6bd6b808b4b16a533474 100644 --- a/README.OPENSOURCE +++ b/README.OPENSOURCE @@ -4,7 +4,7 @@ "License": "Apache License", "License File": " LICENSE ", "Version Number": "2.3.2", - "Upstream URL": "https://github.com/li-xiaojun/XPopup/archive/1906806f1e33ab4ae6758dff84643ad1b4cab280.zip", + "Upstream URL": "https://github.com/li-xiaojun/XPopup", "Description": "Powerful, interactive, and silky general pop-up window" } ] diff --git a/README.md b/README.md index 3b26e28e0cb01eb2e3f0ddcd4fa6f0e8ba894c20..1f6b4b2f543ccae52098dd7baddbbad902f1af5c 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,13 @@ |:---:|:---:| ||| -|Drawer弹窗| 全屏弹窗(可作为Ability替代品,搭配十几个动画使用更佳)| +|自定义底部弹窗| 全屏弹窗(可作为Ability替代品)| |:---:|:---:| -||| +||| -|Position自由定位弹窗(放在屏幕任意地方) | 自定义底部弹窗| +|Position自由定位弹窗(放在屏幕任意地方) | Drawer弹窗| |:---:|:---:| -||| +||| |自定义弹窗和自定义动画 | 内置优雅美观的动画器,可搭配弹窗结合使用| |:---:|:---:| @@ -66,7 +66,7 @@ allprojects{ mavenCentral() } } -implementation 'io.openharmony.tpc.thirdlib:XPopup:1.0.9' +implementation 'io.openharmony.tpc.thirdlib:XPopup:1.1.0' ``` ## entry运行要求 diff --git a/changelog.md b/changelog.md index 811e1eb92005ce11439d12eef115336e3280c660..ec892f81d856edb22f850be8fc21bba5cdbacf24 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,11 @@ -## 1.0.9 +##1.1.0 +1.解决弹窗被软键盘遮盖的问题 + +2.解决弹窗destroy后不释放资源的问题 + +3.解决部分弹窗会出现双重阴影背景的问题 + +## 1.0.9 1.修复dialog模式设置返回键不关闭弹窗功能失效的问题 2.修复Attach弹窗在不同设备下显示位置不同的问题 @@ -54,11 +61,13 @@ 11.设置按下返回键、点击弹窗外面是否关闭弹窗 -12.设置是否自动打开输入法(暂时仅Dialog模式支持) +12.Popup移动到软键盘上面 -13.设置是否半透明背景(暂时仅Component模式支持) +13.设置是否自动打开输入法(暂时仅Dialog模式支持) -14.设置是否点击事件透传(暂时仅Component模式支持,滑动事件暂时无法拦截) +14.设置是否半透明背景(暂时仅Component模式支持) + +15.设置是否点击事件透传(暂时仅Component模式支持,滑动事件暂时无法拦截) 未支持部分: @@ -72,12 +81,10 @@ 5.应用后台弹出Xpopup -6.Popup移动到软键盘上面 - -7.设置是否高斯模糊背景 +6.设置是否高斯模糊背景 -8.设置是否显示状态栏阴影 +7.设置是否显示状态栏阴影 -9.设置是否显示状态栏 +8.设置是否显示状态栏 -10.设置是否显示导航栏 \ No newline at end of file +9.设置是否显示导航栏 \ No newline at end of file diff --git a/entry/src/main/java/com/lxj/xpopupdemo/MainAbility.java b/entry/src/main/java/com/lxj/xpopupdemo/MainAbility.java index 4355b858a12ee5e09161ce0e62b38a274672d2a1..59d1aff632214f1d5a3b5e4b5ce19fc8adb8c7af 100644 --- a/entry/src/main/java/com/lxj/xpopupdemo/MainAbility.java +++ b/entry/src/main/java/com/lxj/xpopupdemo/MainAbility.java @@ -4,7 +4,9 @@ import com.lxj.xpopup.XPopup; import com.lxj.xpopup.core.BasePopupView; import com.lxj.xpopup.impl.LoadingPopupView; import com.lxj.xpopup.util.ElementUtil; +import com.lxj.xpopup.util.LogUtil; import com.lxj.xpopup.util.XPermission; +import com.lxj.xpopup.util.XPopupUtils; import com.lxj.xpopupdemo.stackLayout.AllAnimatorDemo; import com.lxj.xpopupdemo.stackLayout.CustomAnimatorDemo; import com.lxj.xpopupdemo.stackLayout.CustomPopupDemo; @@ -19,7 +21,10 @@ import ohos.agp.components.PageSlider; import ohos.agp.components.PageSliderProvider; import ohos.agp.components.RadioButton; import ohos.agp.components.RadioContainer; +import ohos.eventhandler.EventHandler; +import ohos.eventhandler.EventRunner; import ohos.multimodalinput.event.KeyEvent; +import ohos.system.version.SystemVersion; import java.util.ArrayList; @@ -33,7 +38,6 @@ public class MainAbility extends Ability { ArrayList pageview; RadioContainer radioContainer; private PageSlider pageSlider; - private Component content; @Override public void onStart(Intent intent) { @@ -43,8 +47,7 @@ public class MainAbility extends Ability { StatusBarUtils.setStatusBarColor(this, ElementUtil.getColor(this, ResourceTable.Color_colorBar)); // 暂未实现的效果先移除出去 ((RadioContainer) findComponentById(ResourceTable.Id_radio_container)).removeComponentById(ResourceTable.Id_rb_jubu); - content = findComponentById(ResourceTable.Id_content); - QuickStartDemo view0 = new QuickStartDemo(this, content); + QuickStartDemo view0 = new QuickStartDemo(this); ComponentContainer view1 = new PartShadowDemo(this); ComponentContainer view2 = new ImageViewerDemo(this); ComponentContainer view3 = new AllAnimatorDemo(this); @@ -69,6 +72,18 @@ public class MainAbility extends Ability { loadingPopupView.show(); loadingPopupView.delayDismiss(1200); + new EventHandler(EventRunner.getMainEventRunner()).postTask(new Runnable() { + @Override + public void run() { + String str = "deviceHeight:" + XPopupUtils.getScreenHeight(MainAbility.this) + + " hapHeight:" + XPopupUtils.getAppHeight(MainAbility.this) + + " statusHeight:" + XPopupUtils.getStatusBarHeight(radioContainer) + + " navHeight:" + XPopupUtils.getNavBarHeight(radioContainer) + + " 设备SDK版本:" + SystemVersion.getApiVersion(); + LogUtil.debug("XPopup", str); + } + }, 100); + // 数据适配器 PageSliderProvider mPagerAdapter = new PageSliderProvider() { @Override diff --git a/entry/src/main/java/com/lxj/xpopupdemo/custom/PagerBottomPopup.java b/entry/src/main/java/com/lxj/xpopupdemo/custom/PagerBottomPopup.java index 18abb468fd005dd2f861a1d0c983bb93e0f1d9a3..9b6326a21bd4376178ef8102f020cbc5f3ba92b9 100644 --- a/entry/src/main/java/com/lxj/xpopupdemo/custom/PagerBottomPopup.java +++ b/entry/src/main/java/com/lxj/xpopupdemo/custom/PagerBottomPopup.java @@ -51,7 +51,7 @@ public class PagerBottomPopup extends BottomPopupView { @Override protected int getMaxHeight() { - return (int) (XPopupUtils.getScreenHeight(getContext()) * .85f); + return (int) (XPopupUtils.getAppHeight(getContext()) * .85f); } class PAdapter extends PageSliderProvider { diff --git a/entry/src/main/java/com/lxj/xpopupdemo/custom/ZhihuCommentPopup.java b/entry/src/main/java/com/lxj/xpopupdemo/custom/ZhihuCommentPopup.java index 28fd1eed6d4d59b73807411f9b3b98017697eb22..c0e74cbc5e1d9d963284198858809a309c447b84 100644 --- a/entry/src/main/java/com/lxj/xpopupdemo/custom/ZhihuCommentPopup.java +++ b/entry/src/main/java/com/lxj/xpopupdemo/custom/ZhihuCommentPopup.java @@ -45,6 +45,7 @@ public class ZhihuCommentPopup extends BottomPopupView { final CustomEditTextBottomPopup textBottomPopup = new CustomEditTextBottomPopup(getContext()); new XPopup.Builder(getContext()) .autoOpenSoftInput(true) + .setComponent(ZhihuCommentPopup.this) // 用于获取页面根容器,监听页面高度变化,解决输入法盖住弹窗的问题 .setPopupCallback(new SimpleCallback() { @Override public void onShow(BasePopupView popupView) { @@ -106,6 +107,6 @@ public class ZhihuCommentPopup extends BottomPopupView { @Override protected int getMaxHeight() { - return (int) (XPopupUtils.getScreenHeight(getContext()) * .7f); + return (int) (XPopupUtils.getAppHeight(getContext()) * .7f); } } \ No newline at end of file diff --git a/entry/src/main/java/com/lxj/xpopupdemo/stackLayout/CustomPopupDemo.java b/entry/src/main/java/com/lxj/xpopupdemo/stackLayout/CustomPopupDemo.java index 7a8b5c2123a3b304f4995d1c67c9065ff74b3d2e..5fddd233ba5eff4f7b33ca7df80857dd76ac5d7e 100644 --- a/entry/src/main/java/com/lxj/xpopupdemo/stackLayout/CustomPopupDemo.java +++ b/entry/src/main/java/com/lxj/xpopupdemo/stackLayout/CustomPopupDemo.java @@ -56,6 +56,7 @@ public class CustomPopupDemo extends BaseStackLayout { new XPopup.Builder(getContext()) .popupAnimation(data[position]) .autoOpenSoftInput(true) + .setComponent(listContainer) // 用于获取页面根容器,监听页面高度变化,解决输入法盖住弹窗的问题 .asCustom(customPopup) .show(); } diff --git a/entry/src/main/java/com/lxj/xpopupdemo/stackLayout/QuickStartDemo.java b/entry/src/main/java/com/lxj/xpopupdemo/stackLayout/QuickStartDemo.java index 947c49f3d79fa12b5a151d088972e5f857da5684..70ec5971aa45499be9f8994f073359105c6910bb 100644 --- a/entry/src/main/java/com/lxj/xpopupdemo/stackLayout/QuickStartDemo.java +++ b/entry/src/main/java/com/lxj/xpopupdemo/stackLayout/QuickStartDemo.java @@ -33,11 +33,9 @@ import ohos.hiviewdfx.HiLogLabel; public class QuickStartDemo extends BaseStackLayout implements Component.ClickedListener { private static final String TAG = QuickStartDemo.class.getName(); - private Component content; - public QuickStartDemo(Context context, Component content) { + public QuickStartDemo(Context context) { super(context); - this.content = content; } @Override @@ -100,7 +98,8 @@ public class QuickStartDemo extends BaseStackLayout implements Component.Clicked popupView = new XPopup.Builder(getContext()) .dismissOnBackPressed(false) // 点击返回键是否消失 .dismissOnTouchOutside(true) // 点击外部是否消失 - .isComponentMode(true, content) // Component实现模式 + .setPopupCallback(new DemoXPopupListener()) + .isComponentMode(true, component) // Component实现模式 .asConfirm("哈哈", "床前明月光,疑是地上霜;举头望明月,低头思故乡。", "取消", "确定", new OnConfirmListener() { @@ -131,6 +130,7 @@ public class QuickStartDemo extends BaseStackLayout implements Component.Clicked .hasStatusBarShadow(false) // 暂无实现 .autoOpenSoftInput(true) .isDarkTheme(true) + .setComponent(component) // 用于获取页面根容器,监听页面高度变化,解决输入法盖住弹窗的问题 .setPopupCallback(new DemoXPopupListener()) .asInputConfirm("我是标题", null, null, "我是默认Hint文字", new OnInputConfirmListener() { @@ -235,7 +235,7 @@ public class QuickStartDemo extends BaseStackLayout implements Component.Clicked .hasShadowBg(false) .isDestroyOnDismiss(true) // 对于只使用一次的弹窗,推荐设置这个 .atView(component) // 依附于所点击的View,内部会自动判断在上方或者下方显示 - .isComponentMode(true, content) // Component实现模式 + .isComponentMode(true, component) // Component实现模式 .asAttachList(new String[]{"分享", "编辑", "不带icon不带icon", "分享分享分享"}, new int[]{ResourceTable.Media_icon, ResourceTable.Media_icon}, new OnSelectListener() { @@ -249,7 +249,7 @@ public class QuickStartDemo extends BaseStackLayout implements Component.Clicked new XPopup.Builder(getContext()) .hasShadowBg(false) // 去掉半透明背景 .atView(component) - .isComponentMode(true, content) // Component实现模式 + .isComponentMode(true, component) // Component实现模式 .asCustom(new CustomAttachPopup(getContext())) .show(); break; @@ -258,7 +258,7 @@ public class QuickStartDemo extends BaseStackLayout implements Component.Clicked .isDestroyOnDismiss(true) // 对于只使用一次的弹窗,推荐设置这个 .atView(component) .hasShadowBg(false) // 去掉半透明背景 - .isComponentMode(true, content) // Component实现模式 + .isComponentMode(true, component) // Component实现模式 .asCustom(new CustomAttachPopup2(getContext())).show(); break; case ResourceTable.Id_btnShowDrawerLeft: // 像DrawerLayout一样的Drawer弹窗 @@ -279,6 +279,7 @@ public class QuickStartDemo extends BaseStackLayout implements Component.Clicked new XPopup.Builder(getContext()) .hasStatusBarShadow(true) .autoOpenSoftInput(true) + .setComponent(component) // 用于获取页面根容器,监听页面高度变化,解决输入法盖住弹窗的问题 .asCustom(new CustomFullScreenPopup(getContext())) .show(); break; @@ -286,6 +287,7 @@ public class QuickStartDemo extends BaseStackLayout implements Component.Clicked new XPopup.Builder(getContext()) .autoOpenSoftInput(true) .isDestroyOnDismiss(true) // 对于只使用一次的弹窗,推荐设置这个 + .setComponent(component) // 用于获取页面根容器,监听页面高度变化,解决输入法盖住弹窗的问题 .asCustom(new CustomEditTextBottomPopup(getContext())) .show(); break; diff --git a/entry/src/main/resources/base/layout/ability_main.xml b/entry/src/main/resources/base/layout/ability_main.xml index fef22494d4d0aae2e945b161bf6afa317755f3c5..4f97a094736a164e65a145177c7fb2a418168913 100644 --- a/entry/src/main/resources/base/layout/ability_main.xml +++ b/entry/src/main/resources/base/layout/ability_main.xml @@ -1,7 +1,6 @@ @@ -11,7 +10,7 @@ ohos:width="match_parent" ohos:background_element="$color:colorBar" ohos:padding="16vp" - ohos:text="XPopup-1.0.8" + ohos:text="XPopup-1.1.0" ohos:text_color="#fff" ohos:text_size="20fp" ohos:text_weight="600"/> diff --git a/library/src/main/java/com/lxj/xpopup/XPopup.java b/library/src/main/java/com/lxj/xpopup/XPopup.java index 882faf22c317dd9ddc977ccdb6c0cf23bb8970d5..5d086ed0f98d40c656fcac34cfefe42587374c83 100644 --- a/library/src/main/java/com/lxj/xpopup/XPopup.java +++ b/library/src/main/java/com/lxj/xpopup/XPopup.java @@ -30,6 +30,7 @@ import com.lxj.xpopup.util.EventUtil; import com.lxj.xpopup.util.LogUtil; import ohos.agp.colors.RgbColor; import ohos.agp.components.Component; +import ohos.agp.components.ComponentContainer; import ohos.agp.components.Image; import ohos.agp.render.render3d.math.Quaternion; import ohos.agp.utils.LayoutAlignment; @@ -95,7 +96,7 @@ public class XPopup { } if ("xpopup".equals(component.getTag()) && event.getAction() == TouchEvent.POINT_MOVE) { // 长按发送,阻断父View拦截 - LogUtil.debug("XPopup", "后修完善"); + LogUtil.debug("XPopup", "后续完善"); } if (event.getAction() == TouchEvent.PRIMARY_POINT_UP) { // 长按结束,恢复阻断 @@ -259,7 +260,7 @@ public class XPopup { /** * 是否自动打开输入法,当弹窗包含输入框时很有用,默认为false * - * @param autoOpenSoftInput 是否自动打开输入法,暂未实现 + * @param autoOpenSoftInput 是否自动打开输入法 * @return Builder构造器对象 */ public Builder autoOpenSoftInput(Boolean autoOpenSoftInput) { @@ -270,7 +271,7 @@ public class XPopup { /** * 当弹出输入法时,弹窗是否要移动到输入法之上,默认为true。如果不移动,弹窗很有可能被输入法盖住 * - * @param isMoveUpToKeyboard 当弹出输入法时,弹窗是否要移动到输入法之上,暂未实现 + * @param isMoveUpToKeyboard 当弹出输入法时,弹窗是否要移动到输入法之上 * @return Builder构造器对象 */ public Builder moveUpToKeyboard(Boolean isMoveUpToKeyboard) { @@ -475,12 +476,30 @@ public class XPopup { * XPopup的弹窗默认是Dialog实现,该方法设置为true则切换为Component实现 * * @param componentMode 是否是Component实现,默认是false - * @param contentRoot Component实现时需要传入Ability根布局(控件) - * @return + * @param comonent Component实现时需要传入Ability根布局中的任意一个控件 + * @return Builder构造器对象 + */ + public Builder isComponentMode(boolean componentMode, Component comonent) { + ComponentContainer decorView = ComponentUtil.getDecorView(comonent); + this.popupInfo.isComponentMode = componentMode && decorView != null; + if (decorView != null) { + this.popupInfo.contentRoot = decorView.getComponentAt(0); + } + return this; + } + + /** + * 获取页面根容器,用于监听软键盘的高度变化0 + * 若弹窗中没有会被软键盘遮盖住的TextFiled控件,则无需调用此方法 + * + * @param comonent 页面中的任意一个控件 + * @return Builder构造器对象 */ - public Builder isComponentMode(boolean componentMode, Component contentRoot) { - this.popupInfo.isComponentMode = contentRoot != null; - this.popupInfo.contentRoot = contentRoot; + public Builder setComponent(Component comonent) { + ComponentContainer decorView = ComponentUtil.getDecorView(comonent); + if (decorView != null) { + this.popupInfo.contentRoot = decorView.getComponentAt(0); + } return this; } diff --git a/library/src/main/java/com/lxj/xpopup/core/AttachPopupView.java b/library/src/main/java/com/lxj/xpopup/core/AttachPopupView.java index b117f109c2a8fafccab4377a6b1848f8ee704c2b..90929dbac1721e3a760ddf16f412238d3bd0969c 100644 --- a/library/src/main/java/com/lxj/xpopup/core/AttachPopupView.java +++ b/library/src/main/java/com/lxj/xpopup/core/AttachPopupView.java @@ -98,12 +98,12 @@ public abstract class AttachPopupView extends BasePopupView { public float translationY = 0; // 弹窗显示的位置不能超越Window高度 - float maxY = XPopupUtils.getScreenHeight(getContext()); + float maxY = XPopupUtils.getAppHeight(getContext()); int overflow = XPopupUtils.vp2px(getContext(), 10); float centerY = 0; public void doAttach() { - maxY = XPopupUtils.getScreenHeight(getContext()) - overflow; + maxY = XPopupUtils.getAppHeight(getContext()) - overflow; final boolean isRTL = XPopupUtils.isLayoutRtl(getContext()); // 0. 判断是依附于某个点还是某个View if (popupInfo.touchPoint != null) { @@ -113,7 +113,7 @@ public abstract class AttachPopupView extends BasePopupView { centerY = popupInfo.touchPoint.getY(); // 依附于指定点,尽量优先放在下方,当不够的时候在显示在上方 if ((popupInfo.touchPoint.getY() + getPopupContentView().getHeight()) > maxY) { // 如果下方放不下,超出window高度 - isShowUp = popupInfo.touchPoint.getY() > XPopupUtils.getScreenHeight(getContext()) / 2; + isShowUp = popupInfo.touchPoint.getY() > XPopupUtils.getAppHeight(getContext()) / 2; } else { isShowUp = false; } @@ -122,7 +122,7 @@ public abstract class AttachPopupView extends BasePopupView { // 限制最大宽高 ComponentContainer.LayoutConfig params = getPopupContentView().getLayoutConfig(); int maxHeight = (int) (isShowUpToTarget() ? (popupInfo.touchPoint.getY() - overflow) - : (XPopupUtils.getScreenHeight(getContext()) - popupInfo.touchPoint.getY() - overflow)); + : (XPopupUtils.getAppHeight(getContext()) - popupInfo.touchPoint.getY() - overflow)); int maxWidth = (int) (isShowLeft ? (XPopupUtils.getWindowWidth(getContext()) - popupInfo.touchPoint.getX() - overflow) : (popupInfo.touchPoint.getX() - overflow)); if (getPopupContentView().getHeight() > maxHeight) { params.height = maxHeight; @@ -185,7 +185,7 @@ public abstract class AttachPopupView extends BasePopupView { // 修正高度,弹窗的高有可能超出window区域 ComponentContainer.LayoutConfig params = getPopupContentView().getLayoutConfig(); - int maxHeight = isShowUpToTarget() ? (rect.top - overflow) : (XPopupUtils.getScreenHeight(getContext()) - rect.bottom - overflow); + int maxHeight = isShowUpToTarget() ? (rect.top - overflow) : (XPopupUtils.getAppHeight(getContext()) - rect.bottom - overflow); int maxWidth = isShowLeft ? (XPopupUtils.getWindowWidth(getContext()) - rect.left - overflow) : (rect.right - overflow); if (getPopupContentView().getHeight() > maxHeight) { params.height = maxHeight; @@ -194,7 +194,6 @@ public abstract class AttachPopupView extends BasePopupView { params.width = maxWidth; } getPopupContentView().setLayoutConfig(params); - if (isRTL) { translationX = isShowLeft ? -(XPopupUtils.getWindowWidth(getContext()) - rect.left - getPopupContentView().getWidth() - defaultOffsetX) : -(XPopupUtils.getWindowWidth(getContext()) - rect.right + defaultOffsetX); @@ -240,7 +239,7 @@ public abstract class AttachPopupView extends BasePopupView { protected boolean isShowUpToTarget() { if (popupInfo.positionByWindowCenter) { // 目标在屏幕上半方,弹窗显示在下;反之,则在上 - return centerY > XPopupUtils.getScreenHeight(getContext()) / 2; + return centerY > XPopupUtils.getAppHeight(getContext()) / 2; } // 默认是根据Material规范定位,优先显示在目标下方,下方距离不足才显示在上方 return (isShowUp || popupInfo.popupPosition == PopupPosition.Top) diff --git a/library/src/main/java/com/lxj/xpopup/core/BasePopupView.java b/library/src/main/java/com/lxj/xpopup/core/BasePopupView.java index 8075f2c9d5181916d07c5ccac14ed42a10765dfa..9ef3ba73b99d338c604a626714a1305e91ee6ad5 100644 --- a/library/src/main/java/com/lxj/xpopup/core/BasePopupView.java +++ b/library/src/main/java/com/lxj/xpopup/core/BasePopupView.java @@ -11,17 +11,15 @@ import com.lxj.xpopup.animator.ShadowBgAnimator; import com.lxj.xpopup.animator.TranslateAlphaAnimator; import com.lxj.xpopup.animator.TranslateAnimator; import com.lxj.xpopup.enums.PopupStatus; +import com.lxj.xpopup.impl.FullScreenPopupView; import com.lxj.xpopup.impl.PartShadowPopupView; +import com.lxj.xpopup.util.ComponentUtil; import com.lxj.xpopup.util.EventUtil; import com.lxj.xpopup.util.KeyboardUtils; -import com.lxj.xpopup.util.LogUtil; import com.lxj.xpopup.util.XPopupUtils; import com.lxj.xpopup.widget.ShadowLayout; import ohos.aafwk.ability.Ability; import ohos.aafwk.ability.AbilityPackage; -import ohos.aafwk.ability.Lifecycle; -import ohos.aafwk.ability.LifecycleStateObserver; -import ohos.aafwk.content.Intent; import ohos.agp.components.Component; import ohos.agp.components.Component.BindStateChangedListener; import ohos.agp.components.ComponentContainer; @@ -44,7 +42,7 @@ import static com.lxj.xpopup.enums.PopupAnimation.NoAnimation; * Description: 弹窗基类 * Create by lxj, at 2018/12/7 */ -public abstract class BasePopupView extends StackLayout implements BindStateChangedListener, Component.TouchEventListener, LifecycleStateObserver { +public abstract class BasePopupView extends StackLayout implements BindStateChangedListener, Component.TouchEventListener { public PopupInfo popupInfo; protected PopupAnimator popupContentAnimator; @@ -54,6 +52,7 @@ public abstract class BasePopupView extends StackLayout implements BindStateChan public PopupStatus popupStatus = PopupStatus.Dismiss; protected boolean isCreated = false; protected ShadowLayout shadowLayout; + public boolean hasMoveUp = false; private EventHandler handler = new EventHandler(EventRunner.getMainEventRunner()); protected static BasePopupView basePopupView; @@ -136,26 +135,34 @@ public abstract class BasePopupView extends StackLayout implements BindStateChan }; private void detachFromHost() { - if (popupInfo != null && popupInfo.isComponentMode) { + if (popupInfo != null) { + // 先将popup控件移除 ComponentContainer decorView = (ComponentContainer) getComponentParent(); if (decorView != null) { decorView.removeComponent(this); } - } else { - if (dialog != null) { - dialog.destroy(); - } + } + if (dialog != null) { + dialog.destroy(); } } public Window getHostWindow() { if (popupInfo != null && popupInfo.isComponentMode) { - return ((Ability) getContext()).getWindow(); + return ((Ability) popupInfo.contentRoot.getContext()).getWindow(); } else { return dialog == null ? null : dialog.getWindow(); } } + protected ComponentContainer getWindowDecorView() { + if (popupInfo.contentRoot != null) { + return ComponentUtil.getDecorView(popupInfo.contentRoot); + } else { + return null; + } + } + protected void initAnimator() { // 优先使用自定义的动画器 if (popupInfo.customAnimator != null) { @@ -170,7 +177,7 @@ public abstract class BasePopupView extends StackLayout implements BindStateChan } // 3. 初始化动画执行器 - if (popupInfo.hasShadowBg) { + if (popupInfo.hasShadowBg && !popupInfo.hasBlurBg && popupInfo.isComponentMode) { shadowBgAnimator.initAnimator(); } if (popupInfo.hasBlurBg && blurAnimator != null) { @@ -187,6 +194,10 @@ public abstract class BasePopupView extends StackLayout implements BindStateChan return this; } popupStatus = PopupStatus.Showing; + if (popupInfo.isRequestFocus && popupInfo.contentRoot != null) { + // 显示弹窗之前,应该隐藏输入法 + KeyboardUtils.hideSoftInput(popupInfo.contentRoot); + } if (!popupInfo.isComponentMode && dialog != null && dialog.isShowing()) { return BasePopupView.this; } @@ -199,6 +210,32 @@ public abstract class BasePopupView extends StackLayout implements BindStateChan public void run() { // 1. add PopupView to its dialog. attachToHost(); + + // 2.注册对话框监听器 + KeyboardUtils.registerSoftInputChangedListener(BasePopupView.this, new KeyboardUtils.OnSoftInputChangedListener() { + @Override + public void onSoftInputChanged(int height) { + if (popupInfo != null && popupInfo.xPopupCallback != null) { + popupInfo.xPopupCallback.onKeyBoardStateChanged(BasePopupView.this, height); + } + if (height == 0) { // 说明对话框隐藏 + XPopupUtils.moveDown(BasePopupView.this); + } else { + // when show keyboard,move up + // 全屏弹窗特殊处理,等show之后再移动 + if (BasePopupView.this instanceof FullScreenPopupView && popupStatus == PopupStatus.Showing) { + return; + } + if (BasePopupView.this instanceof PartShadowPopupView && popupStatus == PopupStatus.Showing) { + return; + } + XPopupUtils.moveUpToKeyboard(height, BasePopupView.this); + hasMoveUp = true; + } + } + }); + + // 3.do init,game start. init(); } }; @@ -206,9 +243,6 @@ public abstract class BasePopupView extends StackLayout implements BindStateChan public FullScreenDialog dialog; private void attachToHost() { - if (getContext() instanceof Ability) { - ((Ability) getContext()).getLifecycle().addObserver(this); - } if (popupInfo != null && popupInfo.isComponentMode) { // component实现 ComponentContainer decorView = (ComponentContainer) popupInfo.contentRoot.getComponentParent(); @@ -249,8 +283,8 @@ public abstract class BasePopupView extends StackLayout implements BindStateChan popupInfo.xPopupCallback.onShow(BasePopupView.this); } // 再次检测移动距离 - if (dialog != null) { - LogUtil.debug("XPopup", "waiting for improvement"); + if (getHostWindow() != null && KeyboardUtils.getSoftInputHeight(BasePopupView.this) > 0 && !hasMoveUp) { + XPopupUtils.moveUpToKeyboard(KeyboardUtils.getSoftInputHeight(BasePopupView.this), BasePopupView.this); } } }; @@ -625,8 +659,10 @@ public abstract class BasePopupView extends StackLayout implements BindStateChan if (popupInfo.isRequestFocus) { // 让根布局拿焦点,避免布局内RecyclerView类似布局获取焦点导致布局滚动 - if (popupInfo.decorView != null) { - LogUtil.debug("XPopup", "waiting for improvement"); + ComponentContainer windowDecorView = getWindowDecorView(); + if (windowDecorView != null) { + windowDecorView.setFocusable(FOCUS_ADAPTABLE); + windowDecorView.setTouchFocusable(true); } } @@ -676,17 +712,6 @@ public abstract class BasePopupView extends StackLayout implements BindStateChan protected void onShow() { } - @Override - public void onStateChanged(Lifecycle.Event event, Intent intent) { - onDestroy(); - } - - public void onDestroy() { - onComponentUnboundFromWindow(null); - detachFromHost(); - destroy(); - } - public void destroy() { if (popupInfo != null) { popupInfo.atView = null; @@ -700,9 +725,6 @@ public abstract class BasePopupView extends StackLayout implements BindStateChan dialog.contentView = null; dialog = null; } - if (getContext() != null && getContext() instanceof Ability) { - ((Ability) getContext()).getLifecycle().removeObserver(this); - } if (blurAnimator != null && blurAnimator.decorBitmap != null) { if (!blurAnimator.decorBitmap.isReleased()) { blurAnimator.decorBitmap.release(); @@ -718,9 +740,7 @@ public abstract class BasePopupView extends StackLayout implements BindStateChan public void onComponentUnboundFromWindow(Component component) { handler.removeAllEvent(); if (popupInfo != null) { - if (popupInfo.decorView != null) { - KeyboardUtils.removeLayoutChangeListener(popupInfo.decorView, BasePopupView.this); - } + KeyboardUtils.removeLayoutChangeListener(BasePopupView.this); if (!popupInfo.isComponentMode && dialog != null && dialog.isShowing()) { dialog.destroy(); } @@ -728,9 +748,6 @@ public abstract class BasePopupView extends StackLayout implements BindStateChan destroy(); } } - if (getContext() != null && getContext() instanceof Ability) { - ((Ability) getContext()).getLifecycle().removeObserver(this); - } popupStatus = PopupStatus.Dismiss; showSoftInputTask = null; } diff --git a/library/src/main/java/com/lxj/xpopup/core/BottomPopupView.java b/library/src/main/java/com/lxj/xpopup/core/BottomPopupView.java index 724a62efae46e1bd3522a5349b5a76208d2f0baf..9718c13e181a0195fbca9d53d9f4d2615a85fb88 100644 --- a/library/src/main/java/com/lxj/xpopup/core/BottomPopupView.java +++ b/library/src/main/java/com/lxj/xpopup/core/BottomPopupView.java @@ -62,7 +62,7 @@ public class BottomPopupView extends BasePopupView { if (popupInfo.xPopupCallback != null) { popupInfo.xPopupCallback.onDrag(BottomPopupView.this, value, percent, isScrollUp); } - if (popupInfo.hasShadowBg && !popupInfo.hasBlurBg) { + if (popupInfo.hasShadowBg && !popupInfo.hasBlurBg && popupInfo.isComponentMode) { setBackground(ElementUtil.getShapeElement(shadowBgAnimator.calculateBgColor(percent))); } } @@ -105,7 +105,7 @@ public class BottomPopupView extends BasePopupView { @Override protected PopupAnimator getPopupAnimator() { - return new TranslateAnimator(getPopupContentView(), PopupAnimation.TranslateFromBottom); + return new TranslateAnimator(getPopupImplView(), PopupAnimation.TranslateFromBottom); } @Override diff --git a/library/src/main/java/com/lxj/xpopup/core/DrawerPopupView.java b/library/src/main/java/com/lxj/xpopup/core/DrawerPopupView.java index 9b16de106a09e4a812cc6d3e7bafeaad56fb9328..5ef8f21105e0ae941d40c09cf7217ccb90a2792b 100644 --- a/library/src/main/java/com/lxj/xpopup/core/DrawerPopupView.java +++ b/library/src/main/java/com/lxj/xpopup/core/DrawerPopupView.java @@ -44,7 +44,7 @@ public abstract class DrawerPopupView extends BasePopupView { super.initPopupContent(); getPopupImplView().setTranslationX(popupInfo.offsetX); getPopupImplView().setTranslationY(popupInfo.offsetY); - drawerLayout.hasShadowBg(popupInfo.hasShadowBg); + drawerLayout.hasShadowBg(popupInfo.hasShadowBg && popupInfo.isComponentMode); drawerLayout.dismissOnTouchOutside(popupInfo.isDismissOnTouchOutside); drawerLayout.setDrawerPosition(popupInfo.popupPosition == null ? PopupPosition.Left : popupInfo.popupPosition); drawerLayout.enableDrag(popupInfo.enableDrag); diff --git a/library/src/main/java/com/lxj/xpopup/core/FullScreenDialog.java b/library/src/main/java/com/lxj/xpopup/core/FullScreenDialog.java index dd177d1c378c3b95e4753bc87cfa61f71c82039c..c879a1e2180a8300163b30e2ebd286513d438eb1 100644 --- a/library/src/main/java/com/lxj/xpopup/core/FullScreenDialog.java +++ b/library/src/main/java/com/lxj/xpopup/core/FullScreenDialog.java @@ -1,7 +1,7 @@ package com.lxj.xpopup.core; import com.lxj.xpopup.util.LogUtil; -import com.lxj.xpopup.util.WindowUtil; +import com.lxj.xpopup.util.XPopupUtils; import ohos.agp.components.ComponentContainer; import ohos.agp.window.dialog.CommonDialog; import ohos.agp.window.service.WindowManager; @@ -30,7 +30,7 @@ public class FullScreenDialog extends CommonDialog { getWindow().setLayoutConfig(layoutConfig); } setTransparent(true); - setSize(WindowUtil.getWindowWdith(context), WindowUtil.getWindowHeight(context)); + setSize(XPopupUtils.getWindowWidth(context), XPopupUtils.getAppHeight(context)); if (!contentView.popupInfo.isRequestFocus) { // 不获取焦点 LogUtil.debug("XPopup", "waiting for improvement"); diff --git a/library/src/main/java/com/lxj/xpopup/core/PopupInfo.java b/library/src/main/java/com/lxj/xpopup/core/PopupInfo.java index 1971bf3c9a8c94f666e901280af3861022a831d9..dfd5e547057b3eee96cac3bb2f6f322dd910f8d0 100644 --- a/library/src/main/java/com/lxj/xpopup/core/PopupInfo.java +++ b/library/src/main/java/com/lxj/xpopup/core/PopupInfo.java @@ -54,7 +54,7 @@ public class PopupInfo { public boolean isDestroyOnDismiss = false; // 是否关闭后进行资源释放 public boolean positionByWindowCenter = false; // 是否已屏幕中心进行定位,默认根据Material范式进行定位 public boolean isComponentMode = false; // 是否是Component实现,默认是Dialog实现 - public Component contentRoot; // Component实现时需要传入Ability根布局(控件) + public Component contentRoot; // Component实现和监听软键盘高度变化时需要获取Ability根布局(控件) public Component getAtView() { return atView; diff --git a/library/src/main/java/com/lxj/xpopup/util/ComponentUtil.java b/library/src/main/java/com/lxj/xpopup/util/ComponentUtil.java index 7864c122e309696def0d5534eed39063800e81d0..006f28912b9630a103405246dadf0750357f7e23 100644 --- a/library/src/main/java/com/lxj/xpopup/util/ComponentUtil.java +++ b/library/src/main/java/com/lxj/xpopup/util/ComponentUtil.java @@ -15,6 +15,7 @@ package com.lxj.xpopup.util; import ohos.agp.components.Component; +import ohos.agp.components.ComponentContainer; import ohos.agp.components.ComponentParent; import ohos.agp.utils.Rect; @@ -47,12 +48,16 @@ public class ComponentUtil { * @param component 根容器中的任意一个控件 * @return 根容器 */ - public static Component getDecorView(Component component) { - ComponentParent componentParent = component.getComponentParent(); - if (componentParent == null) { - return component; + public static ComponentContainer getDecorView(Component component) { + if (component != null) { + ComponentParent componentParent = component.getComponentParent(); + if (componentParent == null) { + return (ComponentContainer) component; + } else { + return getDecorView((Component) componentParent); + } } else { - return getDecorView((Component) componentParent); + return null; } } } diff --git a/library/src/main/java/com/lxj/xpopup/util/KeyboardUtils.java b/library/src/main/java/com/lxj/xpopup/util/KeyboardUtils.java index 28080db5e72a2fee7948cbe2975c8e4e2ee17cd1..59443f8002101d9f515d14b1eb548442fc424dc0 100644 --- a/library/src/main/java/com/lxj/xpopup/util/KeyboardUtils.java +++ b/library/src/main/java/com/lxj/xpopup/util/KeyboardUtils.java @@ -3,6 +3,10 @@ package com.lxj.xpopup.util; import com.lxj.xpopup.core.BasePopupView; import ohos.agp.components.Component; import ohos.agp.components.TextField; +import ohos.agp.utils.Rect; + +import java.util.ArrayList; +import java.util.HashMap; /** * Description: @@ -11,13 +15,61 @@ import ohos.agp.components.TextField; public final class KeyboardUtils { public static int sDecorViewInvisibleHeightPre; + private static HashMap listenerMap = new HashMap<>(); private KeyboardUtils() { - throw new UnsupportedOperationException("u can't instantiate me..."); + + } + + /** + * Register soft input changed listener. + * + * @param listener The soft input changed listener. + */ + public static void registerSoftInputChangedListener(final BasePopupView popupView, final OnSoftInputChangedListener listener) { + sDecorViewInvisibleHeightPre = getSoftInputHeight(popupView); + listenerMap.put(popupView, listener); + + if (popupView.popupInfo.contentRoot != null) { + // 设置了页面根容器,则用页面根容器监听页面高度变化 + popupView.popupInfo.contentRoot.setLayoutRefreshedListener(new Component.LayoutRefreshedListener() { + @Override + public void onRefreshed(Component component) { + component.getContext().getUITaskDispatcher().delayDispatch(new Runnable() { + @Override + public void run() { + int height = getSoftInputHeight(popupView); + if (sDecorViewInvisibleHeightPre != height) { + //通知所有弹窗的监听器输入法高度变化了 + for (OnSoftInputChangedListener changedListener : listenerMap.values()) { + changedListener.onSoftInputChanged(height); + } + sDecorViewInvisibleHeightPre = height; + } + } + }, 10); + } + }); + } else { + // 没有页面根容器,则无法监听软键盘高度变化 + LogUtil.debug("XPopup", "如果要监听软键盘高度变化,请调用.setComponent(component)方法设置一个页面中的控件"); + } } - public static void removeLayoutChangeListener(Component decorView, BasePopupView popupView) { + public static void removeLayoutChangeListener(BasePopupView popupView) { + listenerMap.remove(popupView); + } + /** + * 获取软键盘的高度 + * + * @param component 任意一个页面中的控件 + * @return 高度,单位px + */ + public static int getSoftInputHeight(Component component) { + Rect rect = new Rect(); + component.getWindowVisibleRect(rect); + return rect.bottom == 0 ? 0 : XPopupUtils.getScreenHeight(component.getContext()) - rect.bottom; } /** @@ -32,8 +84,19 @@ public final class KeyboardUtils { } } + /** + * 隐藏输入法 + * + * @param component 布局中的任意一个控件 + */ public static void hideSoftInput(Component component) { - + if (component != null) { + ArrayList textFields = new ArrayList<>(); + XPopupUtils.findAllEditText(textFields, ComponentUtil.getDecorView(component)); + for (int i = 0; i < textFields.size(); i++) { + textFields.get(i).clearFocus(); + } + } } public interface OnSoftInputChangedListener { diff --git a/library/src/main/java/com/lxj/xpopup/util/WindowUtil.java b/library/src/main/java/com/lxj/xpopup/util/WindowUtil.java deleted file mode 100644 index 6e276744c9cf38bdabe586f2dd23c23643366f52..0000000000000000000000000000000000000000 --- a/library/src/main/java/com/lxj/xpopup/util/WindowUtil.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2021 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.lxj.xpopup.util; - -import ohos.app.Context; - -/** - * 窗口工具类 - */ -public class WindowUtil { - - /** - * 获取屏幕宽度 - * - * @param context 上下文 - * @return 屏幕宽度,单位px - */ - public static int getWindowWdith(Context context) { - return context.getResourceManager().getDeviceCapability().width * context.getResourceManager().getDeviceCapability().screenDensity / 160; - } - - /** - * 获取屏幕高度 - * - * @param context 上下文 - * @return 屏幕高度,单位px - */ - public static int getWindowHeight(Context context) { - return context.getResourceManager().getDeviceCapability().height * context.getResourceManager().getDeviceCapability().screenDensity / 160; - } - -} diff --git a/library/src/main/java/com/lxj/xpopup/util/XPopupUtils.java b/library/src/main/java/com/lxj/xpopup/util/XPopupUtils.java index 0c6d43556e24fc6bed439c28e4c9d3ed88b4f7c0..233cbd416ce12348ad3f48b66f5880c4768cba88 100644 --- a/library/src/main/java/com/lxj/xpopup/util/XPopupUtils.java +++ b/library/src/main/java/com/lxj/xpopup/util/XPopupUtils.java @@ -1,8 +1,16 @@ package com.lxj.xpopup.util; import com.lxj.xpopup.core.AttachPopupView; +import com.lxj.xpopup.core.BasePopupView; +import com.lxj.xpopup.core.BottomPopupView; +import com.lxj.xpopup.core.CenterPopupView; +import com.lxj.xpopup.core.PositionPopupView; import com.lxj.xpopup.enums.ImageType; +import com.lxj.xpopup.impl.FullScreenPopupView; +import com.lxj.xpopup.impl.PartShadowPopupView; import com.lxj.xpopup.interfaces.XPopupImageLoader; +import ohos.agp.animation.Animator; +import ohos.agp.animation.AnimatorValue; import ohos.agp.colors.RgbColor; import ohos.agp.components.Component; import ohos.agp.components.ComponentContainer; @@ -17,6 +25,8 @@ import ohos.agp.render.Texture; import ohos.agp.utils.Color; import ohos.agp.utils.Rect; import ohos.agp.utils.RectFloat; +import ohos.agp.window.service.Display; +import ohos.agp.window.service.DisplayManager; import ohos.app.Context; import ohos.app.Environment; import ohos.eventhandler.EventHandler; @@ -61,10 +71,22 @@ public class XPopupUtils { * 获取屏幕的高度,包含状态栏,导航栏 * * @param context 上下文 - * @return 屏幕的高度,包含状态栏,导航栏 + * @return 高度,单位px */ public static int getScreenHeight(Context context) { - return context.getResourceManager().getDeviceCapability().height * context.getResourceManager().getDeviceCapability().screenDensity / 160; + Display display = DisplayManager.getInstance().getDefaultDisplay(context).get(); + return display.getRealAttributes().height; + } + + /** + * 获取应用界面可见高度,不包状态栏、导航栏 + * + * @param context 上下文 + * @return 高度,单位px + */ + public static int getAppHeight(Context context) { + Display display = DisplayManager.getInstance().getDefaultDisplay(context).get(); + return display.getAttributes().height; } /** @@ -79,13 +101,14 @@ public class XPopupUtils { } /** - * 获取状态栏高度,暂无实现,需要开发者传入 + * 获取状态栏高度 * - * @param attachPopupView AttachPopupView - * @return 状态栏高度 + * @param component 任意一个处于布局中的控件 + * @return 状态栏高度,单位px */ - public static int getStatusBarHeight(AttachPopupView attachPopupView) { - return 0; + public static int getStatusBarHeight(Component component) { + int[] locationOnScreen = ComponentUtil.getDecorView(component).getLocationOnScreen(); + return locationOnScreen[1]; } /** @@ -93,8 +116,11 @@ public class XPopupUtils { * * @return the navigation bar's height */ - public static int getNavBarHeight() { - return 0; + public static int getNavBarHeight(Component component) { + int screenHeight = getScreenHeight(component.getContext()); + int appHeight = getAppHeight(component.getContext()); + int statusBarHeight = getStatusBarHeight(component); + return screenHeight - appHeight - statusBarHeight; } /** @@ -205,7 +231,7 @@ public class XPopupUtils { public static void findAllEditText(ArrayList list, ComponentContainer group) { for (int i = 0; i < group.getChildCount(); i++) { Component component = group.getComponentAt(i); - if (component instanceof TextField && component.getVisibility() == Component.VISIBLE) { + if (component instanceof TextField) { list.add((TextField) component); } else if (component instanceof ComponentContainer) { findAllEditText(list, (ComponentContainer) component); @@ -213,6 +239,116 @@ public class XPopupUtils { } } + private static int correctKeyboardHeight = 0; + + public static void moveUpToKeyboard(final int keyboardHeight, final BasePopupView pv) { + correctKeyboardHeight = keyboardHeight; + moveUpToKeyboardInternal(correctKeyboardHeight, pv); + } + + private static void moveUpToKeyboardInternal(int keyboardHeight, BasePopupView pv) { + if (pv.popupInfo == null || !pv.popupInfo.isMoveUpToKeyboard) { + return; + } + // 暂时忽略PartShadow弹窗和AttachPopupView + if (pv instanceof PositionPopupView || pv instanceof AttachPopupView) { + return; + } + // 判断是否盖住输入框 + ArrayList allEts = new ArrayList<>(); + findAllEditText(allEts, pv); + TextField focusEt = null; + for (TextField et : allEts) { + if (et.isFocused()) { + focusEt = et; + break; + } + } + + int dy = 0; + int popupHeight = pv.getPopupContentView().getHeight(); + int popupWidth = pv.getPopupContentView().getWidth(); + if (pv.getPopupImplView() != null) { + popupHeight = Math.min(popupHeight, pv.getPopupImplView().getEstimatedHeight()); + popupWidth = Math.min(popupWidth, pv.getPopupImplView().getEstimatedWidth()); + } + + int screenHeight = pv.getEstimatedHeight(); + int focusEtTop = 0; + int focusBottom = 0; + if (focusEt != null) { + int[] locations = focusEt.getLocationOnScreen(); + focusEtTop = locations[1]; + focusBottom = focusEtTop + focusEt.getEstimatedHeight(); + } + // 执行上移 + if (pv instanceof FullScreenPopupView || (popupWidth == XPopupUtils.getWindowWidth(pv.getContext()) && popupHeight == screenHeight)) { + // 如果是全屏弹窗,特殊处理,只要输入框没被盖住,就不移动 + if (focusBottom + keyboardHeight < screenHeight) { + return; + } + } + if (pv instanceof FullScreenPopupView) { + int overflowHeight = focusBottom + keyboardHeight - screenHeight; + if (focusEt != null && overflowHeight > 0) { + dy = overflowHeight; + } + } else if (pv instanceof CenterPopupView) { + int popupBottom = (screenHeight + popupHeight) / 2; + int targetY = popupBottom + keyboardHeight - screenHeight; + if (focusEt != null && focusEtTop - targetY < 0) { + targetY += focusEtTop - targetY - getStatusBarHeight(pv); // 限制不能被状态栏遮住 + } + dy = Math.max(0, targetY); + } else if (pv instanceof BottomPopupView) { + dy = keyboardHeight; + if (focusEt != null && focusEtTop - dy < 0) { + dy += focusEtTop - dy - getStatusBarHeight(pv); // 限制不能被状态栏遮住 + } + } + + // dy=0说明没有触发移动,有些弹窗有translationY,不能影响它们 + if (dy == 0 && pv.getPopupContentView().getTranslationY() != 0) { + return; + } + + int finalDy = dy; + AnimatorValue animatorValue = new AnimatorValue(); + animatorValue.setDuration(200); + animatorValue.setCurveType(Animator.CurveType.OVERSHOOT); + animatorValue.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() { + @Override + public void onUpdate(AnimatorValue animatorValue, float v) { + pv.getPopupContentView().setTranslationY(-finalDy * v); + } + }); + animatorValue.start(); + } + + public static void moveDown(BasePopupView pv) { + // 暂时忽略PartShadow弹窗和AttachPopupView + if (pv instanceof PositionPopupView || pv instanceof AttachPopupView) { + return; + } + Component animComponent; + if (pv instanceof PartShadowPopupView) { + animComponent = pv.getPopupImplView(); + } else { + animComponent = pv.getPopupContentView(); + } + float translationY = animComponent.getTranslationY(); + AnimatorValue animatorValue = new AnimatorValue(); + animatorValue.setDuration(100); + animatorValue.setCurveType(Animator.CurveType.OVERSHOOT); + animatorValue.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() { + @Override + public void onUpdate(AnimatorValue animatorValue, float v) { + pv.getPopupContentView().setTranslationY((1 - v) * translationY); + } + }); + animatorValue.start(); + } + private static Context mContext; public static void saveBmpToAlbum(final Context context, final XPopupImageLoader imageLoader, final String url) { diff --git a/screenshot/attach1.gif b/screenshot/attach1.gif index a0b8913df58eff2553d0faf9d524561b08cee99d..ad3646572228d8ed332d2b62887116b863b8c2bf 100644 Binary files a/screenshot/attach1.gif and b/screenshot/attach1.gif differ diff --git a/screenshot/attach2.gif b/screenshot/attach2.gif index fb3a58fb2f558d11dafc0c67ed377b37b62f1e6c..cee88317c6202f244a596e8a4418726b60429775 100644 Binary files a/screenshot/attach2.gif and b/screenshot/attach2.gif differ diff --git a/screenshot/bottom1.gif b/screenshot/bottom1.gif index 78762dc3f70116b39d56b95e08e9d02bb17b233a..c504df02ebf5b6bd8c45958d3f00d77b97392e48 100644 Binary files a/screenshot/bottom1.gif and b/screenshot/bottom1.gif differ diff --git a/screenshot/bottom2.gif b/screenshot/bottom2.gif index 3469a71abcbbdedffd52f7936f97936124be57d6..b8468228b005a8997795bdb4e06aabc3bdc962e7 100644 Binary files a/screenshot/bottom2.gif and b/screenshot/bottom2.gif differ diff --git a/screenshot/full.gif b/screenshot/full.gif index de2dd8797c0e7870825ed27d13605e583bce01cd..d388ea7df1db80a09d2705f9ed651cf59c0980bd 100644 Binary files a/screenshot/full.gif and b/screenshot/full.gif differ diff --git a/screenshot/input.gif b/screenshot/input.gif index faf0ec2c9f38922bf742ff8710d5a0abaf6f3f55..2a27dc243d858f9042976bf4d3f3ce2db9b243ec 100644 Binary files a/screenshot/input.gif and b/screenshot/input.gif differ diff --git a/screenshot/inset1.gif b/screenshot/inset1.gif index c37650c5ede4f7ce3e25d36019ceaa18314c9385..953dd0c0ef3af8850d79a3f358d961ed7944f312 100644 Binary files a/screenshot/inset1.gif and b/screenshot/inset1.gif differ diff --git a/screenshot/inset2.gif b/screenshot/inset2.gif index 70e47f0e8c42b38490bb9ccf08658b3d3b41df7e..d0b6057fb28f96d037a8ade66a0d636b49bdcce7 100644 Binary files a/screenshot/inset2.gif and b/screenshot/inset2.gif differ diff --git a/screenshot/search.gif b/screenshot/search.gif index 39bd6e96e8d12bfa2ab47ec683da4fba392bdbac..050c0895e2c3f058d5aa0039788836806c735f2d 100644 Binary files a/screenshot/search.gif and b/screenshot/search.gif differ