PopTip.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. package com.kongzue.dialogx.dialogs;
  2. import android.animation.Animator;
  3. import android.graphics.Rect;
  4. import android.view.View;
  5. import android.view.ViewGroup;
  6. import android.view.animation.AccelerateInterpolator;
  7. import android.view.animation.Animation;
  8. import android.view.animation.AnimationUtils;
  9. import android.view.animation.DecelerateInterpolator;
  10. import android.widget.ImageView;
  11. import android.widget.LinearLayout;
  12. import android.widget.RelativeLayout;
  13. import android.widget.TextView;
  14. import androidx.annotation.ColorInt;
  15. import androidx.annotation.IdRes;
  16. import com.kongzue.dialogx.DialogX;
  17. import com.kongzue.dialogx.R;
  18. import com.kongzue.dialogx.impl.AnimatorListenerEndCallBack;
  19. import com.kongzue.dialogx.interfaces.BaseDialog;
  20. import com.kongzue.dialogx.interfaces.DialogConvertViewInterface;
  21. import com.kongzue.dialogx.interfaces.DialogLifecycleCallback;
  22. import com.kongzue.dialogx.interfaces.DialogXStyle;
  23. import com.kongzue.dialogx.interfaces.OnBackPressedListener;
  24. import com.kongzue.dialogx.interfaces.OnBindView;
  25. import com.kongzue.dialogx.interfaces.OnDialogButtonClickListener;
  26. import com.kongzue.dialogx.interfaces.OnSafeInsetsChangeListener;
  27. import com.kongzue.dialogx.style.MaterialStyle;
  28. import com.kongzue.dialogx.util.TextInfo;
  29. import com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout;
  30. import java.lang.ref.WeakReference;
  31. import java.util.Timer;
  32. import java.util.TimerTask;
  33. /**
  34. * @author: Kongzue
  35. * @github: https://github.com/kongzue/
  36. * @homepage: http://kongzue.com/
  37. * @mail: myzcxhh@live.cn
  38. * @createTime: 2020/10/20 11:59
  39. */
  40. public class PopTip extends BaseDialog {
  41. public static final int TIME_NO_AUTO_DISMISS_DELAY = -1;
  42. protected static WeakReference<PopTip> oldInstance;
  43. protected OnBindView<PopTip> onBindView;
  44. protected DialogLifecycleCallback<PopTip> dialogLifecycleCallback;
  45. protected PopTip me = this;
  46. protected DialogImpl dialogImpl;
  47. protected int enterAnimResId = R.anim.anim_dialogx_default_enter;
  48. protected int exitAnimResId = R.anim.anim_dialogx_default_exit;
  49. private View dialogView;
  50. protected DialogXStyle.PopTipSettings.ALIGN align;
  51. protected OnDialogButtonClickListener onButtonClickListener;
  52. protected boolean autoTintIconInLightOrDarkMode = true;
  53. protected int iconResId;
  54. protected CharSequence message;
  55. protected CharSequence buttonText;
  56. protected TextInfo messageTextInfo;
  57. protected TextInfo buttonTextInfo = new TextInfo().setBold(true);
  58. protected PopTip() {
  59. super();
  60. }
  61. public static PopTip build() {
  62. return new PopTip();
  63. }
  64. public PopTip(OnBindView<PopTip> onBindView) {
  65. super();
  66. this.onBindView = onBindView;
  67. }
  68. public PopTip(CharSequence message) {
  69. super();
  70. this.message = message;
  71. }
  72. public PopTip(int iconResId, CharSequence message) {
  73. super();
  74. this.iconResId = iconResId;
  75. this.message = message;
  76. }
  77. public PopTip(int iconResId, CharSequence message, CharSequence buttonText) {
  78. super();
  79. this.iconResId = iconResId;
  80. this.message = message;
  81. this.buttonText = buttonText;
  82. }
  83. public PopTip(CharSequence message, CharSequence buttonText) {
  84. super();
  85. this.message = message;
  86. this.buttonText = buttonText;
  87. }
  88. public PopTip(CharSequence message, OnBindView<PopTip> onBindView) {
  89. super();
  90. this.message = message;
  91. this.onBindView = onBindView;
  92. }
  93. public PopTip(int iconResId, CharSequence message, OnBindView<PopTip> onBindView) {
  94. super();
  95. this.iconResId = iconResId;
  96. this.message = message;
  97. this.onBindView = onBindView;
  98. }
  99. public PopTip(int iconResId, CharSequence message, CharSequence buttonText, OnBindView<PopTip> onBindView) {
  100. super();
  101. this.iconResId = iconResId;
  102. this.message = message;
  103. this.buttonText = buttonText;
  104. this.onBindView = onBindView;
  105. }
  106. public PopTip(CharSequence message, CharSequence buttonText, OnBindView<PopTip> onBindView) {
  107. super();
  108. this.message = message;
  109. this.buttonText = buttonText;
  110. this.onBindView = onBindView;
  111. }
  112. public static PopTip show(OnBindView<PopTip> onBindView) {
  113. PopTip popTip = new PopTip(onBindView);
  114. popTip.show();
  115. return popTip;
  116. }
  117. public static PopTip show(CharSequence message) {
  118. PopTip popTip = new PopTip(message);
  119. popTip.show();
  120. return popTip;
  121. }
  122. public static PopTip show(CharSequence message, OnBindView<PopTip> onBindView) {
  123. PopTip popTip = new PopTip(message, onBindView);
  124. popTip.show();
  125. return popTip;
  126. }
  127. public static PopTip show(CharSequence message, CharSequence buttonText) {
  128. PopTip popTip = new PopTip(message, buttonText);
  129. popTip.show();
  130. return popTip;
  131. }
  132. public static PopTip show(int iconResId, CharSequence message, OnBindView<PopTip> onBindView) {
  133. PopTip popTip = new PopTip(iconResId, message, onBindView);
  134. popTip.show();
  135. return popTip;
  136. }
  137. public static PopTip show(int iconResId, CharSequence message) {
  138. PopTip popTip = new PopTip(iconResId, message);
  139. popTip.show();
  140. return popTip;
  141. }
  142. public static PopTip show(int iconResId, CharSequence message, CharSequence buttonText) {
  143. PopTip popTip = new PopTip(iconResId, message, buttonText);
  144. popTip.show();
  145. return popTip;
  146. }
  147. public static PopTip show(int iconResId, CharSequence message, CharSequence buttonText, OnBindView<PopTip> onBindView) {
  148. PopTip popTip = new PopTip(iconResId, message, buttonText, onBindView);
  149. popTip.show();
  150. return popTip;
  151. }
  152. public static PopTip show(CharSequence message, CharSequence buttonText, OnBindView<PopTip> onBindView) {
  153. PopTip popTip = new PopTip(message, buttonText, onBindView);
  154. popTip.show();
  155. return popTip;
  156. }
  157. public void show() {
  158. if (DialogX.onlyOnePopTip) {
  159. if (oldInstance != null && oldInstance.get() != null) {
  160. oldInstance.get().dismiss();
  161. }
  162. }
  163. oldInstance = new WeakReference<>(this);
  164. int layoutResId = isLightTheme() ? R.layout.layout_dialogx_poptip_material : R.layout.layout_dialogx_poptip_material_dark;
  165. if (style.popTipSettings() != null) {
  166. if (style.popTipSettings().layout(isLightTheme()) != 0) {
  167. layoutResId = style.popTipSettings().layout(isLightTheme());
  168. }
  169. align = style.popTipSettings().align();
  170. if (align == null) align = DialogXStyle.PopTipSettings.ALIGN.BOTTOM;
  171. enterAnimResId = style.popTipSettings().enterAnimResId(isLightTheme()) != 0 ? style.popTipSettings().enterAnimResId(isLightTheme()) : R.anim.anim_dialogx_default_enter;
  172. exitAnimResId = style.popTipSettings().exitAnimResId(isLightTheme()) != 0 ? style.popTipSettings().exitAnimResId(isLightTheme()) : R.anim.anim_dialogx_default_exit;
  173. }
  174. dialogView = createView(layoutResId);
  175. dialogImpl = new DialogImpl(dialogView);
  176. show(dialogView);
  177. }
  178. protected Timer autoDismissTimer;
  179. public PopTip autoDismiss(long delay) {
  180. if (autoDismissTimer != null) {
  181. autoDismissTimer.cancel();
  182. }
  183. if (delay < 0) return this;
  184. autoDismissTimer = new Timer();
  185. autoDismissTimer.schedule(new TimerTask() {
  186. @Override
  187. public void run() {
  188. dismiss();
  189. }
  190. }, delay);
  191. return this;
  192. }
  193. public PopTip showShort() {
  194. autoDismiss(2000);
  195. return this;
  196. }
  197. public PopTip showLong() {
  198. autoDismiss(3500);
  199. return this;
  200. }
  201. public PopTip noAutoDismiss() {
  202. autoDismiss(TIME_NO_AUTO_DISMISS_DELAY);
  203. return this;
  204. }
  205. public class DialogImpl implements DialogConvertViewInterface {
  206. DialogXBaseRelativeLayout boxRoot;
  207. LinearLayout boxBody;
  208. ImageView imgDialogxPopIcon;
  209. TextView txtDialogxPopText;
  210. RelativeLayout boxCustom;
  211. TextView txtDialogxButton;
  212. public DialogImpl(View convertView) {
  213. boxRoot = convertView.findViewById(R.id.box_root);
  214. boxBody = convertView.findViewById(R.id.box_body);
  215. imgDialogxPopIcon = convertView.findViewById(R.id.img_dialogx_pop_icon);
  216. txtDialogxPopText = convertView.findViewById(R.id.txt_dialogx_pop_text);
  217. boxCustom = convertView.findViewById(R.id.box_custom);
  218. txtDialogxButton = convertView.findViewById(R.id.txt_dialogx_button);
  219. init();
  220. refreshView();
  221. }
  222. @Override
  223. public void init() {
  224. boxRoot.setFocusable(false);
  225. boxRoot.setFocusableInTouchMode(false);
  226. boxRoot.setAutoUnsafePlacePadding(false);
  227. boxRoot.setOnLifecycleCallBack(new DialogXBaseRelativeLayout.OnLifecycleCallBack() {
  228. @Override
  229. public void onShow() {
  230. isShow = true;
  231. boxRoot.setAlpha(0f);
  232. getDialogLifecycleCallback().onShow(me);
  233. if (onBindView != null) onBindView.onBind(me, onBindView.getCustomView());
  234. if (autoDismissTimer == null) {
  235. showShort();
  236. }
  237. }
  238. @Override
  239. public void onDismiss() {
  240. isShow = false;
  241. if (oldInstance.get() == me) oldInstance.clear();
  242. getDialogLifecycleCallback().onDismiss(me);
  243. }
  244. });
  245. RelativeLayout.LayoutParams rlp;
  246. rlp = ((RelativeLayout.LayoutParams) boxBody.getLayoutParams());
  247. if (align == null) align = DialogXStyle.PopTipSettings.ALIGN.BOTTOM;
  248. switch (align) {
  249. case TOP:
  250. rlp.removeRule(RelativeLayout.CENTER_IN_PARENT);
  251. rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
  252. break;
  253. case BOTTOM:
  254. rlp.removeRule(RelativeLayout.CENTER_IN_PARENT);
  255. rlp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
  256. break;
  257. case CENTER:
  258. rlp.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
  259. rlp.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
  260. rlp.addRule(RelativeLayout.CENTER_IN_PARENT);
  261. break;
  262. }
  263. boxBody.setLayoutParams(rlp);
  264. boxRoot.setOnSafeInsetsChangeListener(new OnSafeInsetsChangeListener() {
  265. @Override
  266. public void onChange(Rect unsafeRect) {
  267. if (align == DialogXStyle.PopTipSettings.ALIGN.TOP) {
  268. boxBody.setY(unsafeRect.top);
  269. }
  270. }
  271. });
  272. boxRoot.post(new Runnable() {
  273. @Override
  274. public void run() {
  275. Animation enterAnim = AnimationUtils.loadAnimation(getContext(), enterAnimResId);
  276. enterAnim.setInterpolator(new DecelerateInterpolator(2f));
  277. boxBody.startAnimation(enterAnim);
  278. boxRoot.animate().setDuration(enterAnim.getDuration()).alpha(1f).setInterpolator(new DecelerateInterpolator()).setListener(null);
  279. }
  280. });
  281. txtDialogxButton.setOnClickListener(new View.OnClickListener() {
  282. @Override
  283. public void onClick(View v) {
  284. if (onButtonClickListener != null) {
  285. if (!onButtonClickListener.onClick(me, v)) {
  286. doDismiss(v);
  287. }
  288. } else {
  289. doDismiss(v);
  290. }
  291. }
  292. });
  293. }
  294. @Override
  295. public void refreshView() {
  296. if (backgroundColor != -1) {
  297. tintColor(boxBody, backgroundColor);
  298. }
  299. if (onBindView != null) {
  300. if (onBindView.getCustomView() != null) {
  301. if (onBindView.getCustomView().isAttachedToWindow()) {
  302. boxCustom.removeView(onBindView.getCustomView());
  303. }
  304. ViewGroup.LayoutParams lp = onBindView.getCustomView().getLayoutParams();
  305. if (lp == null) {
  306. lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  307. }
  308. boxCustom.addView(onBindView.getCustomView(), lp);
  309. }
  310. }
  311. showText(txtDialogxPopText, message);
  312. showText(txtDialogxButton, buttonText);
  313. useTextInfo(txtDialogxPopText, messageTextInfo);
  314. useTextInfo(txtDialogxButton, buttonTextInfo);
  315. if (iconResId != 0) {
  316. imgDialogxPopIcon.setVisibility(View.VISIBLE);
  317. imgDialogxPopIcon.setImageResource(iconResId);
  318. if (autoTintIconInLightOrDarkMode) {
  319. imgDialogxPopIcon.setImageTintList(txtDialogxPopText.getTextColors());
  320. } else {
  321. imgDialogxPopIcon.setImageTintList(null);
  322. }
  323. } else {
  324. imgDialogxPopIcon.setVisibility(View.GONE);
  325. }
  326. }
  327. @Override
  328. public void doDismiss(final View v) {
  329. boxRoot.post(new Runnable() {
  330. @Override
  331. public void run() {
  332. if (v != null) v.setEnabled(false);
  333. Animation exitAnim = AnimationUtils.loadAnimation(getContext(), exitAnimResId);
  334. boxBody.startAnimation(exitAnim);
  335. boxRoot.animate().alpha(0f).setInterpolator(new AccelerateInterpolator()).setDuration(exitAnim.getDuration()).setListener(new AnimatorListenerEndCallBack() {
  336. @Override
  337. public void onAnimationEnd(Animator animation) {
  338. dismiss(dialogView);
  339. }
  340. });
  341. }
  342. });
  343. }
  344. }
  345. public void refreshUI() {
  346. if (dialogImpl == null) return;
  347. dialogImpl.refreshView();
  348. }
  349. public void dismiss() {
  350. if (dialogImpl == null) return;
  351. dialogImpl.doDismiss(null);
  352. }
  353. public DialogLifecycleCallback<PopTip> getDialogLifecycleCallback() {
  354. return dialogLifecycleCallback == null ? new DialogLifecycleCallback<PopTip>() {
  355. } : dialogLifecycleCallback;
  356. }
  357. public PopTip setDialogLifecycleCallback(DialogLifecycleCallback<PopTip> dialogLifecycleCallback) {
  358. this.dialogLifecycleCallback = dialogLifecycleCallback;
  359. return this;
  360. }
  361. public OnBackPressedListener getOnBackPressedListener() {
  362. return onBackPressedListener;
  363. }
  364. public PopTip setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
  365. this.onBackPressedListener = onBackPressedListener;
  366. refreshUI();
  367. return this;
  368. }
  369. public PopTip setStyle(DialogXStyle style) {
  370. this.style = style;
  371. return this;
  372. }
  373. public PopTip setTheme(DialogX.THEME theme) {
  374. this.theme = theme;
  375. return this;
  376. }
  377. public boolean isCancelable() {
  378. return cancelable;
  379. }
  380. public PopTip setCancelable(boolean cancelable) {
  381. this.cancelable = cancelable;
  382. refreshUI();
  383. return this;
  384. }
  385. public PopTip.DialogImpl getDialogImpl() {
  386. return dialogImpl;
  387. }
  388. public PopTip setCustomView(OnBindView<PopTip> onBindView) {
  389. this.onBindView = onBindView;
  390. refreshUI();
  391. return this;
  392. }
  393. public View getCustomView() {
  394. if (onBindView == null) return null;
  395. return onBindView.getCustomView();
  396. }
  397. public PopTip removeCustomView() {
  398. this.onBindView.clean();
  399. refreshUI();
  400. return this;
  401. }
  402. public DialogXStyle.PopTipSettings.ALIGN getAlign() {
  403. return align;
  404. }
  405. public PopTip setAlign(DialogXStyle.PopTipSettings.ALIGN align) {
  406. this.align = align;
  407. return this;
  408. }
  409. public int getIconResId() {
  410. return iconResId;
  411. }
  412. public PopTip setIconResId(int iconResId) {
  413. this.iconResId = iconResId;
  414. refreshUI();
  415. return this;
  416. }
  417. public CharSequence getMessage() {
  418. return message;
  419. }
  420. public PopTip setMessage(CharSequence message) {
  421. this.message = message;
  422. refreshUI();
  423. return this;
  424. }
  425. public CharSequence getButtonText() {
  426. return buttonText;
  427. }
  428. public PopTip setButton(CharSequence buttonText) {
  429. this.buttonText = buttonText;
  430. refreshUI();
  431. return this;
  432. }
  433. public PopTip setButton(CharSequence buttonText, OnDialogButtonClickListener onButtonClickListener) {
  434. this.buttonText = buttonText;
  435. this.onButtonClickListener = onButtonClickListener;
  436. refreshUI();
  437. return this;
  438. }
  439. public PopTip setButton(OnDialogButtonClickListener onButtonClickListener) {
  440. this.onButtonClickListener = onButtonClickListener;
  441. return this;
  442. }
  443. public TextInfo getMessageTextInfo() {
  444. return messageTextInfo;
  445. }
  446. public PopTip setMessageTextInfo(TextInfo messageTextInfo) {
  447. this.messageTextInfo = messageTextInfo;
  448. refreshUI();
  449. return this;
  450. }
  451. public TextInfo getButtonTextInfo() {
  452. return buttonTextInfo;
  453. }
  454. public PopTip setButtonTextInfo(TextInfo buttonTextInfo) {
  455. this.buttonTextInfo = buttonTextInfo;
  456. refreshUI();
  457. return this;
  458. }
  459. public OnDialogButtonClickListener getOnButtonClickListener() {
  460. return onButtonClickListener;
  461. }
  462. public PopTip setOnButtonClickListener(OnDialogButtonClickListener onButtonClickListener) {
  463. this.onButtonClickListener = onButtonClickListener;
  464. return this;
  465. }
  466. public boolean isAutoTintIconInLightOrDarkMode() {
  467. return autoTintIconInLightOrDarkMode;
  468. }
  469. public PopTip setAutoTintIconInLightOrDarkMode(boolean autoTintIconInLightOrDarkMode) {
  470. this.autoTintIconInLightOrDarkMode = autoTintIconInLightOrDarkMode;
  471. refreshUI();
  472. return this;
  473. }
  474. public int getBackgroundColor() {
  475. return backgroundColor;
  476. }
  477. public PopTip setBackgroundColor(@ColorInt int backgroundColor) {
  478. this.backgroundColor = backgroundColor;
  479. refreshUI();
  480. return this;
  481. }
  482. }