此文章是我在简书的文章,自行搬到博客园.简书地址:SweetTips: 快意灵动的Android提示库!

源码及所在DEMO已上传至GitHub:SweetTips,欢迎大家提Bug,喜欢的话记得Star或Fork下哈!

1.为什么要写这个库?

上面的问题也可以这样问:有哪些常见的需求,Android原生Toast及Design包中的Snackbar实现起来相对繁琐?Toast:

  1. 原生Toast无法/不方便自定义显示时间;
  2. 原生Toast,需要等待队列中前面的Toast实例显示完毕之后才可以显示,实时性差;
  3. 原生Toast,想在正在显示的Toast实例上显示新的内容并设置新内容的显示时间,实现较繁琐;
  4. 原生Toast,无法/不方便自定义动画;
  5. Android系统版本过多,不同的厂商对系统的定制也很不同,同一段代码在不同的机器上,Toast的样式差异很大,不利于App的一致性体验;

Snackbar:

  • Design包中的Snackbar,无法自定义动画;

2.SweetTips有什么用?

很显然,可以解决上面列举的那些很常见的小问题;

截图:

3.SweetTips的结构?

自定义Toast:SweetToast + 自定义Snackbar:SweetSnackbar + SnackbarUtils:SweetSnackbar的工具类

4.SweetTips的实现思路

SweetToast:

  • 在SweetToastManager中,利用队列实现对SweetToast实例的管理,直接调用SweetToast的show()方法,可以实现和原生Toast几乎一致的体验;
  • 在SweetToastManager中,通过对队列的清空,实现即时显示当前SweetToast实例的内容;
  • 在SweetToast中,通过设置WindowManager.LayoutParams.windowAnimations,实现SweetToast实例自定义的出入场动画;
  • SweetToast支持链式调用,调用尽可能的快捷;

SweetSnackbar:

  • 几乎完全拷贝了Design包中的Snackbar,只是添加了一个设置自定义出入场动画的方法:setAnimations
  • 参照之前写过的一个工具类GitHub:SnackbarUtils,为SweetSnackbar也写了一个工具类,同样支持练市调用,实现'一行代码设置多重属性';

SweetTips.java

  • 这个工具类待完善,是为了通过SweetToast或SweetSnackbar,封装一些比较常用且精美的效果,通过静态方法直接调用,提升开发者一些效率.

另外,为了这个提示库,也花了不少时间收集了一些常用的颜色,保存在Constant.java中,可作为一个通用的工具类适用于不同项目,喜欢的同学尽管拿走.

5.SweetTips的使用限制

SweetToast是通过WindowManager向屏幕添加View来展示提示信息:

params.type = WindowManager.LayoutParams.TYPE_TOAST;

在Manifest.xml中已经声明过权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

在SDK>=23(Android 6)的系统中,用户需要手动允许当前App使用这个权限,才可以正常显示!

6.SweetTips部分代码

  1. /**
  2. * 自定义Toast
  3. *
  4. * 作者:幻海流心
  5. * GitHub:https://github.com/HuanHaiLiuXin
  6. * 邮箱:wall0920@163.com
  7. * 2016/12/13
  8. */
  9.  
  10. public final class SweetToast {
  11. public static final int LENGTH_SHORT = 0;
  12. public static final int LENGTH_LONG = 1;
  13. public static final long SHORT_DELAY = 2000; // 2 seconds
  14. public static final long LONG_DELAY = 3500; // 3.5 seconds
  15. //SweetToast默认背景色
  16. private static int mBackgroundColor = 0XE8484848;
  17. //
  18. private View mContentView = null; //内容区域View
  19. private SweetToastConfiguration mConfiguration = null;
  20. private WindowManager mWindowManager = null;
  21. private boolean showing = false; //是否在展示中
  22. private boolean showEnabled = true; //是否允许展示
  23. private boolean hideEnabled = true; //是否允许移除
  24. private boolean stateChangeEnabled = true; //是否允许改变展示状态
  25.  
  26. public static SweetToast makeText(Context context, CharSequence text){
  27. return makeText(context, text, LENGTH_SHORT);
  28. }
  29. public static SweetToast makeText(View mContentView){
  30. return makeText(mContentView, LENGTH_SHORT);
  31. }
  32. public static SweetToast makeText(Context context, CharSequence text, int duration) {
  33. try {
  34. LayoutInflater inflate = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  35. View v = inflate.inflate(R.layout.transient_notification, null);
  36. TextView tv = (TextView)v.findViewById(R.id.message);
  37. tv.setText(text);
  38. SweetToast sweetToast = new SweetToast();
  39. sweetToast.mContentView = v;
  40. sweetToast.mContentView.setBackgroundDrawable(getBackgroundDrawable(sweetToast, mBackgroundColor));
  41. initConfiguration(sweetToast,duration);
  42. return sweetToast;
  43. }catch (Exception e){
  44. Log.e("幻海流心","e:"+e.getLocalizedMessage()+":69");
  45. }
  46. return null;
  47. }
  48. public static SweetToast makeText(View mContentView, int duration){
  49. SweetToast sweetToast = new SweetToast();
  50. sweetToast.mContentView = mContentView;
  51. initConfiguration(sweetToast,duration);
  52. return sweetToast;
  53. }
  54. private static void initConfiguration(SweetToast sweetToast,int duration){
  55. try {
  56. if(duration < 0){
  57. throw new RuntimeException("显示时长必须>=0!");
  58. }
  59. //1:初始化mWindowManager
  60. sweetToast.mWindowManager = (WindowManager) sweetToast.getContentView().getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
  61. //2:初始化mConfiguration
  62. SweetToastConfiguration mConfiguration = new SweetToastConfiguration();
  63. //2.1:设置显示时间
  64. mConfiguration.setDuration(duration);
  65. //2.2:设置WindowManager.LayoutParams属性
  66. WindowManager.LayoutParams params = new WindowManager.LayoutParams();
  67. final Configuration config = sweetToast.getContentView().getContext().getResources().getConfiguration();
  68. final int gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
  69. params.gravity = gravity;
  70. if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
  71. params.horizontalWeight = 1.0f;
  72. }
  73. if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
  74. params.verticalWeight = 1.0f;
  75. }
  76. params.x = 0;
  77. params.y = sweetToast.getContentView().getContext().getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
  78. params.verticalMargin = 0.0f;
  79. params.horizontalMargin = 0.0f;
  80. params.height = WindowManager.LayoutParams.WRAP_CONTENT;
  81. params.width = WindowManager.LayoutParams.WRAP_CONTENT;
  82. params.format = PixelFormat.TRANSLUCENT;
  83. params.windowAnimations = R.style.Anim_SweetToast;
  84. //在小米5S上实验,前两种type均会报错
  85. params.type = WindowManager.LayoutParams.TYPE_TOAST;
  86. // params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
  87. // params.type = WindowManager.LayoutParams.TYPE_PHONE;
  88. params.setTitle("Toast");
  89. params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
  90. | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
  91. | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
  92. mConfiguration.setParams(params);
  93. sweetToast.setConfiguration(mConfiguration);
  94. }catch (Exception e){
  95. Log.e("幻海流心","e:"+e.getLocalizedMessage()+":120");
  96. }
  97. }
  98. /**
  99. * 根据指定的背景色,获得mToastView的背景drawable实例
  100. * @param backgroundColor
  101. * @return
  102. */
  103. private static ShapeDrawable getBackgroundDrawable(SweetToast sweetToast, @ColorInt int backgroundColor){
  104. try {
  105. ShapeDrawable shapeDrawable = new ShapeDrawable();
  106. DrawableCompat.setTint(shapeDrawable,backgroundColor);
  107. //获取当前设备的屏幕尺寸
  108. //实验发现不同的设备上面,Toast内容区域的padding值并不相同,根据屏幕的宽度分别进行处理,尽量接近设备原生Toast的体验
  109. int widthPixels = sweetToast.getContentView().getResources().getDisplayMetrics().widthPixels;
  110. int heightPixels = sweetToast.getContentView().getResources().getDisplayMetrics().heightPixels;
  111. float density = sweetToast.getContentView().getResources().getDisplayMetrics().density;
  112. if(widthPixels >= 1070){
  113. //例如小米5S:1920 x 1080
  114. shapeDrawable.setPadding((int)(density*13),(int)(density*12),(int)(density*13),(int)(density*12));
  115. }else {
  116. //例如红米2:1280x720
  117. shapeDrawable.setPadding((int)(density*14),(int)(density*13),(int)(density*14),(int)(density*13));
  118. }
  119. float radius = density*8;
  120. float[] outerRadii = new float[]{radius,radius,radius,radius,radius,radius,radius,radius};
  121. int width = sweetToast.getContentView().getWidth();
  122. int height = sweetToast.getContentView().getHeight();
  123. RectF rectF = new RectF(1,1,width-1,height-1);
  124. RoundRectShape roundRectShape = new RoundRectShape(outerRadii,rectF,null);
  125. shapeDrawable.setShape(roundRectShape);
  126. DrawableCompat.setTint(shapeDrawable,backgroundColor);
  127. return shapeDrawable;
  128. }catch (Exception e){
  129. Log.e("幻海流心","e:"+e.getLocalizedMessage()+":154");
  130. }
  131. return null;
  132. }
  133. /**
  134. * 自定义SweetToast实例的入场出场动画
  135. * @param windowAnimations
  136. * @return
  137. */
  138. public SweetToast setWindowAnimations(@StyleRes int windowAnimations){
  139. mConfiguration.getParams().windowAnimations = windowAnimations;
  140. return this;
  141. }
  142. public SweetToast setGravity(int gravity, int xOffset, int yOffset) {
  143. mConfiguration.getParams().gravity = gravity;
  144. mConfiguration.getParams().x = xOffset;
  145. mConfiguration.getParams().y = yOffset;
  146. return this;
  147. }
  148. public SweetToast setMargin(float horizontalMargin, float verticalMargin) {
  149. mConfiguration.getParams().horizontalMargin = horizontalMargin;
  150. mConfiguration.getParams().verticalMargin = verticalMargin;
  151. return this;
  152. }
  153. /**
  154. * 向mContentView中添加View
  155. *
  156. * @param view
  157. * @param index
  158. * @return
  159. */
  160. public SweetToast addView(View view, int index) {
  161. if(mContentView != null && mContentView instanceof ViewGroup){
  162. ((ViewGroup)mContentView).addView(view,index);
  163. }
  164. return this;
  165. }
  166. /**
  167. * 设置SweetToast实例中TextView的文字颜色
  168. *
  169. * @param messageColor
  170. * @return
  171. */
  172. public SweetToast messageColor(@ColorInt int messageColor){
  173. if(mContentView !=null && mContentView.findViewById(R.id.message) != null && mContentView.findViewById(R.id.message) instanceof TextView){
  174. TextView textView = ((TextView) mContentView.findViewById(R.id.message));
  175. textView.setTextColor(messageColor);
  176. }
  177. return this;
  178. }
  179. /**
  180. * 设置SweetToast实例的背景颜色
  181. *
  182. * @param backgroundColor
  183. * @return
  184. */
  185. public SweetToast backgroundColor(@ColorInt int backgroundColor){
  186. if(mContentView!=null){
  187. mContentView.setBackgroundDrawable(getBackgroundDrawable(this, backgroundColor));
  188. }
  189. return this;
  190. }
  191. /**
  192. * 设置SweetToast实例的背景资源
  193. *
  194. * @param background
  195. * @return
  196. */
  197. public SweetToast backgroundResource(@DrawableRes int background){
  198. if(mContentView!=null){
  199. mContentView.setBackgroundResource(background);
  200. }
  201. return this;
  202. }
  203. /**
  204. * 设置SweetToast实例的文字颜色及背景颜色
  205. *
  206. * @param messageColor
  207. * @param backgroundColor
  208. * @return
  209. */
  210. public SweetToast colors(@ColorInt int messageColor, @ColorInt int backgroundColor) {
  211. messageColor(messageColor);
  212. backgroundColor(backgroundColor);
  213. return this;
  214. }
  215. /**
  216. * 设置SweetToast实例的文字颜色及背景资源
  217. *
  218. * @param messageColor
  219. * @param background
  220. * @return
  221. */
  222. public SweetToast textColorAndBackground(@ColorInt int messageColor, @DrawableRes int background) {
  223. messageColor(messageColor);
  224. backgroundResource(background);
  225. return this;
  226. }
  227.  
  228. /**
  229. * 设置SweetToast实例的宽高
  230. * 很有用的功能,参考了简书上的文章:http://www.jianshu.com/p/491b17281c0a
  231. * @param width SweetToast实例的宽度,单位是pix
  232. * @param height SweetToast实例的高度,单位是pix
  233. * @return
  234. */
  235. public SweetToast size(int width, int height){
  236. if(mContentView!=null && mContentView instanceof LinearLayout){
  237. mContentView.setMinimumWidth(width);
  238. mContentView.setMinimumHeight(height);
  239. ((LinearLayout)mContentView).setGravity(Gravity.CENTER);
  240. try {
  241. TextView textView = ((TextView) mContentView.findViewById(R.id.message));
  242. LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams();
  243. params.width = LinearLayout.LayoutParams.MATCH_PARENT;
  244. params.height = LinearLayout.LayoutParams.MATCH_PARENT;
  245. textView.setLayoutParams(params);
  246. textView.setGravity(Gravity.CENTER);
  247. }catch (Exception e){
  248. Log.e("幻海流心","e:"+e.getLocalizedMessage());
  249. }
  250. }
  251. return this;
  252. }
  253.  
  254. /**
  255. * 设置SweetToast实例的显示位置:左上
  256. * @return
  257. */
  258. public SweetToast leftTop(){
  259. return setGravity(Gravity.LEFT|Gravity.TOP,0,0);
  260. }
  261. /**
  262. * 设置SweetToast实例的显示位置:右上
  263. * @return
  264. */
  265. public SweetToast rightTop(){
  266. return setGravity(Gravity.RIGHT|Gravity.TOP,0,0);
  267. }
  268. /**
  269. * 设置SweetToast实例的显示位置:左下
  270. * @return
  271. */
  272. public SweetToast leftBottom(){
  273. return setGravity(Gravity.LEFT|Gravity.BOTTOM,0,0);
  274. }
  275. /**
  276. * 设置SweetToast实例的显示位置:右下
  277. * @return
  278. */
  279. public SweetToast rightBottom(){
  280. return setGravity(Gravity.RIGHT|Gravity.BOTTOM,0,0);
  281. }
  282. /**
  283. * 设置SweetToast实例的显示位置:上中
  284. * @return
  285. */
  286. public SweetToast topCenter(){
  287. return setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL,0,0);
  288. }
  289. /**
  290. * 设置SweetToast实例的显示位置:下中
  291. * @return
  292. */
  293. public SweetToast bottomCenter(){
  294. return setGravity(Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL,0,0);
  295. }
  296. /**
  297. * 设置SweetToast实例的显示位置:左中
  298. * @return
  299. */
  300. public SweetToast leftCenter(){
  301. return setGravity(Gravity.LEFT|Gravity.CENTER_VERTICAL,0,0);
  302. }
  303. /**
  304. * 设置SweetToast实例的显示位置:右中
  305. * @return
  306. */
  307. public SweetToast rightCenter(){
  308. return setGravity(Gravity.RIGHT|Gravity.CENTER_VERTICAL,0,0);
  309. }
  310. /**
  311. * 设置SweetToast实例的显示位置:正中
  312. * @return
  313. */
  314. public SweetToast center(){
  315. return setGravity(Gravity.CENTER,0,0);
  316. }
  317. /**
  318. * 将SweetToast实例显示在指定View的顶部
  319. * @param targetView 指定View
  320. * @param statusHeight 状态栏显示情况下,状态栏的高度
  321. * @return
  322. */
  323. public SweetToast layoutAbove(View targetView, int statusHeight){
  324. if(mContentView!=null){
  325. int[] locations = new int[2];
  326. targetView.getLocationOnScreen(locations);
  327. //必须保证指定View的顶部可见
  328. int screenHeight = ScreenUtil.getScreenHeight(mContentView.getContext());
  329. if(locations[1] > statusHeight&&locations[1]<screenHeight){
  330. setGravity(Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL,0,screenHeight - locations[1]);
  331. }
  332. }
  333. return this;
  334. }
  335. /**
  336. * 将SweetToast实例显示在指定View的底部
  337. * @param targetView
  338. * @param statusHeight
  339. * @return
  340. */
  341. public SweetToast layoutBellow(View targetView, int statusHeight){
  342. if(mContentView!=null){
  343. int[] locations = new int[2];
  344. targetView.getLocationOnScreen(locations);
  345. //必须保证指定View的底部可见
  346. int screenHeight = ScreenUtil.getScreenHeight(mContentView.getContext());
  347. if(locations[1]+targetView.getHeight() > statusHeight&&locations[1]+targetView.getHeight()<screenHeight){
  348. setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL,0,locations[1]+targetView.getHeight()-statusHeight);
  349. }
  350. }
  351. return this;
  352. }
  353.  
  354. /********************************************** SweetToast显示及移除 **********************************************/
  355. Handler mHandler = new Handler();
  356. Runnable mHide = new Runnable() {
  357. @Override
  358. public void run() {
  359. handleHide();
  360. }
  361. };
  362. protected void handleHide() {
  363. if(this != null && mContentView != null){
  364. if(stateChangeEnabled){
  365. if(hideEnabled){
  366. if(showing){
  367. mWindowManager.removeView(mContentView);
  368. }
  369. showing = false;
  370. mContentView = null;
  371. }else{
  372. }
  373. }
  374. }
  375. }
  376. protected void handleShow() {
  377. if(mContentView != null){
  378. if(stateChangeEnabled){
  379. if(showEnabled){
  380. try {
  381. mWindowManager.addView(mContentView,mConfiguration.getParams());
  382. long delay = (mConfiguration.getDuration() == LENGTH_LONG || mConfiguration.getDuration() == Toast.LENGTH_LONG) ? LONG_DELAY : ((mConfiguration.getDuration() == LENGTH_SHORT || mConfiguration.getDuration() == Toast.LENGTH_SHORT)? SHORT_DELAY : mConfiguration.getDuration());
  383. mHandler.postDelayed(mHide,delay);
  384. showing = true;
  385. }catch (Exception e){
  386. Log.e("幻海流心","e:"+e.getLocalizedMessage()+":213");
  387. }
  388. }
  389. }
  390. }
  391. }
  392.  
  393. /**
  394. * 保持当前实例的显示状态:不允许向Window中添加或者移除View
  395. */
  396. protected void removeCallbacks(){
  397. stateChangeEnabled = false;
  398. }
  399.  
  400. /**
  401. * 设置是否允许展示当前实例
  402. * @param showEnabled
  403. */
  404. public void setShowEnabled(boolean showEnabled) {
  405. this.showEnabled = showEnabled;
  406. }
  407.  
  408. /**
  409. * 设置是否允许移除当前实例中的View
  410. * @param hideEnabled
  411. */
  412. public void setHideEnabled(boolean hideEnabled) {
  413. this.hideEnabled = hideEnabled;
  414. }
  415.  
  416. /**
  417. * 设置是否允许改变当前实例的展示状态
  418. * @param stateChangeEnabled
  419. */
  420. public void setStateChangeEnabled(boolean stateChangeEnabled) {
  421. this.stateChangeEnabled = stateChangeEnabled;
  422. }
  423.  
  424. /**
  425. * 将当前实例添加到队列{@link SweetToastManager#queue}中,若队列为空,则加入队列后直接进行展示
  426. */
  427. public void show(){
  428. try {
  429. if (Build.VERSION.SDK_INT >= 23) {
  430. //Android6.0以上,需要动态声明权限
  431. if(mContentView!=null && !Settings.canDrawOverlays(mContentView.getContext().getApplicationContext())) {
  432. //用户还未允许该权限
  433. Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
  434. mContentView.getContext().startActivity(intent);
  435. return;
  436. } else if(mContentView!=null) {
  437. //用户已经允许该权限
  438. SweetToastManager.show(this);
  439. }
  440. } else {
  441. //Android6.0以下,不用动态声明权限
  442. if (mContentView!=null) {
  443. SweetToastManager.show(this);
  444. }
  445. }
  446. // SweetToastManager.show(this);
  447. }catch (Exception e){
  448. Log.e("幻海流心","e:"+e.getLocalizedMessage()+":232");
  449. }
  450. }
  451. /**
  452. * 利用队列{@link SweetToastManager#queue}中正在展示的SweetToast实例,继续展示当前实例的内容
  453. */
  454. public void showByPrevious(){
  455. try {
  456. if (Build.VERSION.SDK_INT >= 23) {
  457. //Android6.0以上,需要动态声明权限
  458. if(mContentView!=null && !Settings.canDrawOverlays(mContentView.getContext().getApplicationContext())) {
  459. //用户还未允许该权限
  460. Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
  461. mContentView.getContext().startActivity(intent);
  462. return;
  463. } else if(mContentView!=null) {
  464. //用户已经允许该权限
  465. SweetToastManager.showByPrevious(this);
  466. }
  467. } else {
  468. //Android6.0以下,不用动态声明权限
  469. if (mContentView!=null) {
  470. SweetToastManager.showByPrevious(this);
  471. }
  472. }
  473. // SweetToastManager.showByPrevious(this);
  474. }catch (Exception e){
  475. Log.e("幻海流心","e:"+e.getLocalizedMessage()+":290");
  476. }
  477. }
  478. /**
  479. * 清空队列{@link SweetToastManager#queue}中已经存在的SweetToast实例,直接展示当前实例的内容
  480. */
  481. public void showImmediate(){
  482. try {
  483. if (Build.VERSION.SDK_INT >= 23) {
  484. //Android6.0以上,需要动态声明权限
  485. if(mContentView!=null && !Settings.canDrawOverlays(mContentView.getContext().getApplicationContext())) {
  486. //用户还未允许该权限
  487. Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
  488. mContentView.getContext().startActivity(intent);
  489. return;
  490. } else if(mContentView!=null) {
  491. //用户已经允许该权限
  492. SweetToastManager.showImmediate(this);
  493. }
  494. } else {
  495. //Android6.0以下,不用动态声明权限
  496. if (mContentView!=null) {
  497. SweetToastManager.showImmediate(this);
  498. }
  499. }
  500. // SweetToastManager.showImmediate(this);
  501. }catch (Exception e){
  502. Log.e("幻海流心","e:"+e.getLocalizedMessage()+":252");
  503. }
  504. }
  505. /**
  506. * 移除当前SweetToast并将mContentView置空
  507. */
  508. public void hide() {
  509. mHandler.post(mHide);
  510. }
  511. /********************************************** SweetToast显示及移除 **********************************************/
  512.  
  513. //Setter&Getter
  514. public View getContentView() {
  515. return mContentView;
  516. }
  517. public void setContentView(View mContentView) {
  518. this.mContentView = mContentView;
  519. }
  520. public SweetToastConfiguration getConfiguration() {
  521. return mConfiguration;
  522. }
  523. public void setConfiguration(SweetToastConfiguration mConfiguration) {
  524. this.mConfiguration = mConfiguration;
  525. }
  526. public WindowManager getWindowManager() {
  527. return mWindowManager;
  528. }
  529. public void setWindowManager(WindowManager mWindowManager) {
  530. this.mWindowManager = mWindowManager;
  531. }
  532. public boolean isShowing() {
  533. return showing;
  534. }
  535. public void setShowing(boolean showing) {
  536. this.showing = showing;
  537. }
  538. }

源码及所在DEMO已上传至GitHub:SweetTips,欢迎大家提Bug,喜欢的话记得Star或Fork下哈!

That's all !

SweetTips: 快意灵动的Android提示库!的更多相关文章

  1. 100个Github上Android开源库

    项目名称 项目简介 1. react-native 这个是 Facebook 在 React.js Conf 2015 大会上推出的基于 JavaScript 的开源框架 React Native, ...

  2. GitHub上排名前100的Android开源库介绍(来自github)

    本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍,至于排名完全是根据 GitHub 搜索 Java 语言选择 (Best Match) 得到的结果,然后过滤了 ...

  3. GitHub Top 100的Android开源库

    摘要: 本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据GitHub搜索Java语言选择「Best M... 本项目主要对目前 GitH ...

  4. GitHub 上排名前 100 的 Android 开源库进行简单的介绍

    若有任何疑问可通过邮件或微博联系我 项目名称 项目简介 1. react-native 这个是 Facebook 在 React.js Conf 2015 大会上推出的基于 JavaScript 的开 ...

  5. 我的Android进阶之旅】GitHub 上排名前 100 的 Android 开源库进行简单的介绍

    GitHub Android Libraries Top 100 简介 本文转载于:https://github.com/Freelander/Android_Data/blob/master/And ...

  6. <Android开源库 ~ 1> GitHub Android Libraries Top 100 简介

    转载自GitHub Android Libraries Top 100 简介 本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据 GitH ...

  7. GitHub上排名前100的Android开源库介绍

    GitHub上排名前100的Android开源库介绍 文章来源: http://www.open-open.com/news/view/1587067#6734290-qzone-1-31660-bf ...

  8. Eclipse中Android公共库的正确建立及调用方法

    Eclipse中Android公共库的正确建立及调用方法 引言 之前一直头痛于没有办法在多个程序中共享资源,用作公共类库的方法也是使用的导出jar再导入的办法,现在终于初步搞明白了,可算解脱了~,分享 ...

  9. [开源项目] Android校验库 - FireEye

    简单易用的Android校验库. 这是一个简单Android校验库,按配置来验证用户输入的表单信息. 仅仅须要几行代码,就可以验证用户输入,而且将验证错误反馈给用户. 它内置了大量经常使用的验证类型, ...

随机推荐

  1. WCF客户端与服务端通信简单入门教程

    服务端 1.新建空白解决方案,然后再空白解决方案中新建:WCF服务应用程序.建完后如图: 2.删掉自动生成的IService1.cs和Service.svc并添加WCF服务文件StudentServi ...

  2. 关于ActiveMQ的一点总结

    ActiveMQ入门 作者:一路向北 摘要:本文主要讲述ActiveMQ的基本知识和使用方法,并简单结合spring使用ActiveMQ. 一.ActiveMQ特性和使用总览 企业消息软件从80年代起 ...

  3. poj 2485 (kruskal算法)

    /*kruskal算法*/ #include <iostream> //#include <fstream> #include <algorithm> using ...

  4. 8259A工作原理描述

    通过初始化编程向8259A写入相应的初始化命令ICW,可以使芯片处于一个规定的基本工作方式,并在此方式下进行工作.8259A的初始化命令字共有4个ICW1-ICW4,进行初始化时要求ICW1-ICW4 ...

  5. 一张图让你快速学会UML(聚合、组合、依赖、继承、接口、类)

    有朋友反映,一上来直接讲设计模式就算理解了,也不知道如何画出类图,那么我们就通过一张图,来图解如何应用UML正确表示类与类之间的关系. 这张图完整讲述了鸟类的生存. 首先是类:在UML中,我们用分成三 ...

  6. 【汇编语言】DEBUG的使用

    在masm for windows中,需要先生存exe文件,然后再点调试按钮. 常用的命令有: R命令:查看.改变CPU寄存器的内容:如果要修改某个寄存器的内容,可以在r的后面接上空格和寄存器名.如: ...

  7. JS 多个参数的传递

    var link = $("<a/>", { href: '/StandardManagement/StandardActivitiesDetail?' + $.par ...

  8. 转载:jsp九大内置对象和四大作用域

    摘要: JSP的九大内置对象: page,application,session,request,response,out,exception,config,pageContext. JSP的四个作用 ...

  9. Java入门第三季排序练习

    package imooc_collection_map_demo; import java.util.ArrayList;import java.util.Collections;import ja ...

  10. 【转】深入理解Major GC, Full GC, CMS

    声明:本文转自http://blog.csdn.net/iter_zc/article/details/41825395,转载务必声明. 很多人都分不清Major GC, Full GC的概念,事实上 ...