deniedPermissions = new ArrayList<>();
+ for (String permission : permissions) {
+ if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_DENIED) {
+ deniedPermissions.add(permission);
+ }
+ }
+ return deniedPermissions;
+ }
+
+ /**
+ * 请求权限结果,对应Activity中onRequestPermissionsResult()方法。
+ */
+ public static void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ if (mRequestCode != -1 && requestCode == mRequestCode) {
+ if (mOnPermissionListener != null) {
+ if (verifyPermissions(grantResults)) {
+ mOnPermissionListener.onPermissionGranted();
+ } else {
+ mOnPermissionListener.onPermissionDenied();
+ }
+ }
+ }
+ }
+
+ /**
+ * 验证所有权限是否都已经授权
+ */
+ private static boolean verifyPermissions(int[] grantResults) {
+ for (int grantResult : grantResults) {
+ if (grantResult != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * 显示提示对话框
+ */
+ public static void showTipsDialog(final Context context) {
+ new AlertDialog.Builder(context)
+ .setTitle("提示信息")
+ .setMessage("当前应用缺少必要权限,该功能暂时无法使用。如若需要,请单击【确定】按钮前往设置中心进行权限授权。")
+ .setNegativeButton("取消", null)
+ .setPositiveButton("确定", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ startAppSettings(context);
+ }
+ }).show();
+ }
+ /**
+ * 启动当前应用设置页面
+ */
+ private static void startAppSettings(Context context) {
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.setData(Uri.parse("package:" + context.getPackageName()));
+ context.startActivity(intent);
+ }
+}
diff --git a/xframe/src/main/java/com/youth/xframe/utils/statusbar/XStatusBar.java b/xframe/src/main/java/com/youth/xframe/utils/statusbar/XStatusBar.java
new file mode 100644
index 0000000..d95d0ba
--- /dev/null
+++ b/xframe/src/main/java/com/youth/xframe/utils/statusbar/XStatusBar.java
@@ -0,0 +1,606 @@
+package com.youth.xframe.utils.statusbar;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.support.annotation.ColorInt;
+import android.support.v4.widget.DrawerLayout;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+
+/**
+ * 状态栏工具类
+ *
+ * 设置状态栏沉浸式或者状态栏颜色
+ */
+public class XStatusBar {
+ public static final int DEFAULT_STATUS_BAR_ALPHA = 0;
+
+ /**
+ * 设置状态栏颜色
+ *
+ * @param activity 需要设置的 activity
+ * @param color 状态栏颜色值
+ */
+ public static void setColor(Activity activity, @ColorInt int color) {
+ setColor(activity, color, DEFAULT_STATUS_BAR_ALPHA);
+ }
+
+ /**
+ * 设置状态栏颜色
+ *
+ * @param activity 需要设置的activity
+ * @param color 状态栏颜色值
+ * @param statusBarAlpha 状态栏透明度
+ */
+
+ public static void setColor(Activity activity, @ColorInt int color, int statusBarAlpha) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ activity.getWindow().setStatusBarColor(calculateStatusColor(color, statusBarAlpha));
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
+ int count = decorView.getChildCount();
+ if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) {
+ decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
+ } else {
+ StatusBarView statusView = createStatusBarView(activity, color, statusBarAlpha);
+ decorView.addView(statusView);
+ }
+ setRootView(activity);
+ }
+ }
+
+ /**
+ * 为滑动返回界面设置状态栏颜色
+ *
+ * @param activity 需要设置的activity
+ * @param color 状态栏颜色值
+ */
+ public static void setColorForSwipeBack(Activity activity, int color) {
+ setColorForSwipeBack(activity, color, DEFAULT_STATUS_BAR_ALPHA);
+ }
+
+ /**
+ * 为滑动返回界面设置状态栏颜色
+ *
+ * @param activity 需要设置的activity
+ * @param color 状态栏颜色值
+ * @param statusBarAlpha 状态栏透明度
+ */
+ public static void setColorForSwipeBack(Activity activity, @ColorInt int color, int statusBarAlpha) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ ViewGroup contentView = ((ViewGroup) activity.findViewById(android.R.id.content));
+ contentView.setPadding(0, getStatusBarHeight(activity), 0, 0);
+ contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
+ setTransparentForWindow(activity);
+ }
+ }
+
+ /**
+ * 设置状态栏纯色 不加半透明效果
+ *
+ * @param activity 需要设置的 activity
+ * @param color 状态栏颜色值
+ */
+ public static void setColorNoTranslucent(Activity activity, @ColorInt int color) {
+ setColor(activity, color, 0);
+ }
+
+ /**
+ * 设置状态栏颜色(5.0以下无半透明效果,不建议使用)
+ *
+ * @param activity 需要设置的 activity
+ * @param color 状态栏颜色值
+ */
+ @Deprecated
+ public static void setColorDiff(Activity activity, @ColorInt int color) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ return;
+ }
+ transparentStatusBar(activity);
+ ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
+ // 移除半透明矩形,以免叠加
+ if (contentView.getChildCount() > 1) {
+ contentView.getChildAt(1).setBackgroundColor(color);
+ } else {
+ contentView.addView(createStatusBarView(activity, color));
+ }
+ setRootView(activity);
+ }
+
+ /**
+ * 使状态栏半透明
+ *
+ * 适用于图片作为背景的界面,此时需要图片填充到状态栏
+ *
+ * @param activity 需要设置的activity
+ */
+ public static void setTranslucent(Activity activity) {
+ setTranslucent(activity, DEFAULT_STATUS_BAR_ALPHA);
+ }
+
+ /**
+ * 使状态栏半透明
+ *
+ * 适用于图片作为背景的界面,此时需要图片填充到状态栏
+ *
+ * @param activity 需要设置的activity
+ * @param statusBarAlpha 状态栏透明度
+ */
+ public static void setTranslucent(Activity activity, int statusBarAlpha) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ return;
+ }
+ setTransparent(activity);
+ addTranslucentView(activity, statusBarAlpha);
+ }
+
+ /**
+ * 针对根布局是 CoordinatorLayout, 使状态栏半透明
+ *
+ * 适用于图片作为背景的界面,此时需要图片填充到状态栏
+ *
+ * @param activity 需要设置的activity
+ * @param statusBarAlpha 状态栏透明度
+ */
+ public static void setTranslucentForCoordinatorLayout(Activity activity, int statusBarAlpha) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ return;
+ }
+ transparentStatusBar(activity);
+ addTranslucentView(activity, statusBarAlpha);
+ }
+
+ /**
+ * 设置状态栏全透明
+ *
+ * @param activity 需要设置的activity
+ */
+ public static void setTransparent(Activity activity) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ return;
+ }
+ transparentStatusBar(activity);
+ setRootView(activity);
+ }
+
+ /**
+ * 使状态栏透明(5.0以上半透明效果,不建议使用)
+ *
+ * 适用于图片作为背景的界面,此时需要图片填充到状态栏
+ *
+ * @param activity 需要设置的activity
+ */
+ @Deprecated
+ public static void setTranslucentDiff(Activity activity) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ // 设置状态栏透明
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ setRootView(activity);
+ }
+ }
+
+ /**
+ * 为DrawerLayout 布局设置状态栏变色
+ *
+ * @param activity 需要设置的activity
+ * @param drawerLayout DrawerLayout
+ * @param color 状态栏颜色值
+ */
+ public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {
+ setColorForDrawerLayout(activity, drawerLayout, color, DEFAULT_STATUS_BAR_ALPHA);
+ }
+
+ /**
+ * 为DrawerLayout 布局设置状态栏颜色,纯色
+ *
+ * @param activity 需要设置的activity
+ * @param drawerLayout DrawerLayout
+ * @param color 状态栏颜色值
+ */
+ public static void setColorNoTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {
+ setColorForDrawerLayout(activity, drawerLayout, color, 0);
+ }
+
+ /**
+ * 为DrawerLayout 布局设置状态栏变色
+ *
+ * @param activity 需要设置的activity
+ * @param drawerLayout DrawerLayout
+ * @param color 状态栏颜色值
+ * @param statusBarAlpha 状态栏透明度
+ */
+ public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color,
+ int statusBarAlpha) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ return;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
+ } else {
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ }
+ // 生成一个状态栏大小的矩形
+ // 添加 statusBarView 到布局中
+ ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
+ if (contentLayout.getChildCount() > 0 && contentLayout.getChildAt(0) instanceof StatusBarView) {
+ contentLayout.getChildAt(0).setBackgroundColor(color);
+ } else {
+ StatusBarView statusBarView = createStatusBarView(activity, color);
+ contentLayout.addView(statusBarView, 0);
+ }
+ // 内容布局不是 LinearLayout 时,设置padding top
+ if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {
+ contentLayout.getChildAt(1)
+ .setPadding(contentLayout.getPaddingLeft(), getStatusBarHeight(activity) + contentLayout.getPaddingTop(),
+ contentLayout.getPaddingRight(), contentLayout.getPaddingBottom());
+ }
+ // 设置属性
+ setDrawerLayoutProperty(drawerLayout, contentLayout);
+ addTranslucentView(activity, statusBarAlpha);
+ }
+
+ /**
+ * 设置 DrawerLayout 属性
+ *
+ * @param drawerLayout DrawerLayout
+ * @param drawerLayoutContentLayout DrawerLayout 的内容布局
+ */
+ private static void setDrawerLayoutProperty(DrawerLayout drawerLayout, ViewGroup drawerLayoutContentLayout) {
+ ViewGroup drawer = (ViewGroup) drawerLayout.getChildAt(1);
+ drawerLayout.setFitsSystemWindows(false);
+ drawerLayoutContentLayout.setFitsSystemWindows(false);
+ drawerLayoutContentLayout.setClipToPadding(true);
+ drawer.setFitsSystemWindows(false);
+ }
+
+ /**
+ * 为DrawerLayout 布局设置状态栏变色(5.0以下无半透明效果,不建议使用)
+ *
+ * @param activity 需要设置的activity
+ * @param drawerLayout DrawerLayout
+ * @param color 状态栏颜色值
+ */
+ @Deprecated
+ public static void setColorForDrawerLayoutDiff(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ // 生成一个状态栏大小的矩形
+ ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
+ if (contentLayout.getChildCount() > 0 && contentLayout.getChildAt(0) instanceof StatusBarView) {
+ contentLayout.getChildAt(0).setBackgroundColor(calculateStatusColor(color, DEFAULT_STATUS_BAR_ALPHA));
+ } else {
+ // 添加 statusBarView 到布局中
+ StatusBarView statusBarView = createStatusBarView(activity, color);
+ contentLayout.addView(statusBarView, 0);
+ }
+ // 内容布局不是 LinearLayout 时,设置padding top
+ if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {
+ contentLayout.getChildAt(1).setPadding(0, getStatusBarHeight(activity), 0, 0);
+ }
+ // 设置属性
+ setDrawerLayoutProperty(drawerLayout, contentLayout);
+ }
+ }
+
+ /**
+ * 为 DrawerLayout 布局设置状态栏透明
+ *
+ * @param activity 需要设置的activity
+ * @param drawerLayout DrawerLayout
+ */
+ public static void setTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout) {
+ setTranslucentForDrawerLayout(activity, drawerLayout, DEFAULT_STATUS_BAR_ALPHA);
+ }
+
+ /**
+ * 为 DrawerLayout 布局设置状态栏透明
+ *
+ * @param activity 需要设置的activity
+ * @param drawerLayout DrawerLayout
+ */
+ public static void setTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout, int statusBarAlpha) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ return;
+ }
+ setTransparentForDrawerLayout(activity, drawerLayout);
+ addTranslucentView(activity, statusBarAlpha);
+ }
+
+ /**
+ * 为 DrawerLayout 布局设置状态栏透明
+ *
+ * @param activity 需要设置的activity
+ * @param drawerLayout DrawerLayout
+ */
+ public static void setTransparentForDrawerLayout(Activity activity, DrawerLayout drawerLayout) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ return;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
+ } else {
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ }
+
+ ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
+ // 内容布局不是 LinearLayout 时,设置padding top
+ if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {
+ contentLayout.getChildAt(1).setPadding(0, getStatusBarHeight(activity), 0, 0);
+ }
+
+ // 设置属性
+ setDrawerLayoutProperty(drawerLayout, contentLayout);
+ }
+
+ /**
+ * 为 DrawerLayout 布局设置状态栏透明(5.0以上半透明效果,不建议使用)
+ *
+ * @param activity 需要设置的activity
+ * @param drawerLayout DrawerLayout
+ */
+ @Deprecated
+ public static void setTranslucentForDrawerLayoutDiff(Activity activity, DrawerLayout drawerLayout) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ // 设置状态栏透明
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ // 设置内容布局属性
+ ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
+ contentLayout.setFitsSystemWindows(true);
+ contentLayout.setClipToPadding(true);
+ // 设置抽屉布局属性
+ ViewGroup vg = (ViewGroup) drawerLayout.getChildAt(1);
+ vg.setFitsSystemWindows(false);
+ // 设置 DrawerLayout 属性
+ drawerLayout.setFitsSystemWindows(false);
+ }
+ }
+
+ /**
+ * 为头部是 ImageView 的界面设置状态栏全透明
+ *
+ * @param activity 需要设置的activity
+ * @param needOffsetView 需要向下偏移的 View
+ */
+ public static void setTransparentForImageView(Activity activity, View needOffsetView) {
+ setTranslucentForImageView(activity, 0, needOffsetView);
+ }
+
+ /**
+ * 为头部是 ImageView 的界面设置状态栏透明(使用默认透明度)
+ *
+ * @param activity 需要设置的activity
+ * @param needOffsetView 需要向下偏移的 View
+ */
+ public static void setTranslucentForImageView(Activity activity, View needOffsetView) {
+ setTranslucentForImageView(activity, DEFAULT_STATUS_BAR_ALPHA, needOffsetView);
+ }
+
+ /**
+ * 为头部是 ImageView 的界面设置状态栏透明
+ *
+ * @param activity 需要设置的activity
+ * @param statusBarAlpha 状态栏透明度
+ * @param needOffsetView 需要向下偏移的 View
+ */
+ public static void setTranslucentForImageView(Activity activity, int statusBarAlpha, View needOffsetView) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ return;
+ }
+ setTransparentForWindow(activity);
+ addTranslucentView(activity, statusBarAlpha);
+ if (needOffsetView != null) {
+ ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) needOffsetView.getLayoutParams();
+ layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin + getStatusBarHeight(activity),
+ layoutParams.rightMargin, layoutParams.bottomMargin);
+ }
+ }
+
+ /**
+ * 为 fragment 头部是 ImageView 的设置状态栏透明
+ *
+ * @param activity fragment 对应的 activity
+ * @param needOffsetView 需要向下偏移的 View
+ */
+ public static void setTranslucentForImageViewInFragment(Activity activity, View needOffsetView) {
+ setTranslucentForImageViewInFragment(activity, DEFAULT_STATUS_BAR_ALPHA, needOffsetView);
+ }
+
+ /**
+ * 为 fragment 头部是 ImageView 的设置状态栏透明
+ *
+ * @param activity fragment 对应的 activity
+ * @param needOffsetView 需要向下偏移的 View
+ */
+ public static void setTransparentForImageViewInFragment(Activity activity, View needOffsetView) {
+ setTranslucentForImageViewInFragment(activity, 0, needOffsetView);
+ }
+
+ /**
+ * 为 fragment 头部是 ImageView 的设置状态栏透明
+ *
+ * @param activity fragment 对应的 activity
+ * @param statusBarAlpha 状态栏透明度
+ * @param needOffsetView 需要向下偏移的 View
+ */
+ public static void setTranslucentForImageViewInFragment(Activity activity, int statusBarAlpha, View needOffsetView) {
+ setTranslucentForImageView(activity, statusBarAlpha, needOffsetView);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ clearPreviousSetting(activity);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////
+
+ @TargetApi(Build.VERSION_CODES.KITKAT)
+ private static void clearPreviousSetting(Activity activity) {
+ ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
+ int count = decorView.getChildCount();
+ if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) {
+ decorView.removeViewAt(count - 1);
+ ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
+ rootView.setPadding(0, 0, 0, 0);
+ }
+ }
+
+ /**
+ * 添加半透明矩形条
+ *
+ * @param activity 需要设置的 activity
+ * @param statusBarAlpha 透明值
+ */
+ private static void addTranslucentView(Activity activity, int statusBarAlpha) {
+ ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
+ if (contentView.getChildCount() > 1) {
+ contentView.getChildAt(1).setBackgroundColor(Color.argb(statusBarAlpha, 0, 0, 0));
+ } else {
+ contentView.addView(createTranslucentStatusBarView(activity, statusBarAlpha));
+ }
+ }
+
+ /**
+ * 生成一个和状态栏大小相同的彩色矩形条
+ *
+ * @param activity 需要设置的 activity
+ * @param color 状态栏颜色值
+ * @return 状态栏矩形条
+ */
+ private static StatusBarView createStatusBarView(Activity activity, @ColorInt int color) {
+ // 绘制一个和状态栏一样高的矩形
+ StatusBarView statusBarView = new StatusBarView(activity);
+ LinearLayout.LayoutParams params =
+ new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
+ statusBarView.setLayoutParams(params);
+ statusBarView.setBackgroundColor(color);
+ return statusBarView;
+ }
+
+ /**
+ * 生成一个和状态栏大小相同的半透明矩形条
+ *
+ * @param activity 需要设置的activity
+ * @param color 状态栏颜色值
+ * @param alpha 透明值
+ * @return 状态栏矩形条
+ */
+ private static StatusBarView createStatusBarView(Activity activity, @ColorInt int color, int alpha) {
+ // 绘制一个和状态栏一样高的矩形
+ StatusBarView statusBarView = new StatusBarView(activity);
+ LinearLayout.LayoutParams params =
+ new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
+ statusBarView.setLayoutParams(params);
+ statusBarView.setBackgroundColor(calculateStatusColor(color, alpha));
+ return statusBarView;
+ }
+
+ /**
+ * 设置根布局参数
+ */
+ private static void setRootView(Activity activity) {
+ ViewGroup parent = (ViewGroup) activity.findViewById(android.R.id.content);
+ for (int i = 0, count = parent.getChildCount(); i < count; i++) {
+ View childView = parent.getChildAt(i);
+ if (childView instanceof ViewGroup) {
+ childView.setFitsSystemWindows(true);
+ ((ViewGroup) childView).setClipToPadding(true);
+ }
+ }
+ }
+
+ /**
+ * 设置透明
+ */
+ private static void setTransparentForWindow(Activity activity) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
+ activity.getWindow()
+ .getDecorView()
+ .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ activity.getWindow()
+ .setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ }
+ }
+
+ /**
+ * 使状态栏透明
+ */
+ @TargetApi(Build.VERSION_CODES.KITKAT)
+ private static void transparentStatusBar(Activity activity) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+ activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
+ } else {
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ }
+ }
+
+ /**
+ * 创建半透明矩形 View
+ *
+ * @param alpha 透明值
+ * @return 半透明 View
+ */
+ private static StatusBarView createTranslucentStatusBarView(Activity activity, int alpha) {
+ // 绘制一个和状态栏一样高的矩形
+ StatusBarView statusBarView = new StatusBarView(activity);
+ LinearLayout.LayoutParams params =
+ new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
+ statusBarView.setLayoutParams(params);
+ statusBarView.setBackgroundColor(Color.argb(alpha, 0, 0, 0));
+ return statusBarView;
+ }
+
+ /**
+ * 获取状态栏高度
+ *
+ * @param context context
+ * @return 状态栏高度
+ */
+ private static int getStatusBarHeight(Context context) {
+ // 获得状态栏高度
+ int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
+ return context.getResources().getDimensionPixelSize(resourceId);
+ }
+
+ /**
+ * 计算状态栏颜色
+ *
+ * @param color color值
+ * @param alpha alpha值
+ * @return 最终的状态栏颜色
+ */
+ private static int calculateStatusColor(@ColorInt int color, int alpha) {
+ float a = 1 - alpha / 255f;
+ int red = color >> 16 & 0xff;
+ int green = color >> 8 & 0xff;
+ int blue = color & 0xff;
+ red = (int) (red * a + 0.5);
+ green = (int) (green * a + 0.5);
+ blue = (int) (blue * a + 0.5);
+ return 0xff << 24 | red << 16 | green << 8 | blue;
+ }
+ public static class StatusBarView extends View {
+ public StatusBarView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public StatusBarView(Context context) {
+ super(context);
+ }
+ }
+}
diff --git a/xframe/src/main/java/com/youth/xframe/widget/NoScrollGridView.java b/xframe/src/main/java/com/youth/xframe/widget/NoScrollGridView.java
new file mode 100644
index 0000000..0c0ce65
--- /dev/null
+++ b/xframe/src/main/java/com/youth/xframe/widget/NoScrollGridView.java
@@ -0,0 +1,36 @@
+package com.youth.xframe.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.GridView;
+
+/**
+ * GridView嵌套在SrcollView中会出现显示不全的情况
+ *
+ * 这个类通过设置不滚动来避免
+ */
+
+public class NoScrollGridView extends GridView {
+ public NoScrollGridView(Context context) {
+ super(context);
+ }
+
+ public NoScrollGridView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public NoScrollGridView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * 重写该方法,设置不滚动
+ */
+ @Override
+ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
+ MeasureSpec.AT_MOST);
+ super.onMeasure(widthMeasureSpec, expandSpec);
+
+ }
+}
diff --git a/xframe/src/main/java/com/youth/xframe/widget/NoScrollListView.java b/xframe/src/main/java/com/youth/xframe/widget/NoScrollListView.java
new file mode 100644
index 0000000..bebd496
--- /dev/null
+++ b/xframe/src/main/java/com/youth/xframe/widget/NoScrollListView.java
@@ -0,0 +1,36 @@
+package com.youth.xframe.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ListView;
+
+
+/**
+ * Listview嵌套在SrcollView中会出现显示不全的情况
+ *
+ * 这个类通过设置不滚动来避免
+ */
+public class NoScrollListView extends ListView {
+
+ public NoScrollListView(Context context) {
+ super(context);
+ }
+
+ public NoScrollListView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public NoScrollListView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+ /**
+ * 重写该方法,设置不滚动
+ */
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
+ MeasureSpec.AT_MOST);
+ super.onMeasure(widthMeasureSpec, expandSpec);
+ }
+
+}
diff --git a/xframe/src/main/java/com/youth/xframe/widget/XLoadingDialog.java b/xframe/src/main/java/com/youth/xframe/widget/XLoadingDialog.java
new file mode 100644
index 0000000..bbf0cc9
--- /dev/null
+++ b/xframe/src/main/java/com/youth/xframe/widget/XLoadingDialog.java
@@ -0,0 +1,61 @@
+package com.youth.xframe.widget;
+
+
+import android.app.Dialog;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.support.annotation.ColorInt;
+import android.text.TextUtils;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.youth.xframe.R;
+import com.youth.xframe.XFrame;
+
+public class XLoadingDialog extends Dialog {
+ private static XLoadingDialog dialog;
+ private Context context;
+ private TextView xTextView;
+
+ public XLoadingDialog(Context context) {
+ super(context, R.style.loading_dialog);
+ this.context=context;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.xloading_dialog);
+ xTextView = (TextView) findViewById(R.id.loading_message);
+ }
+
+ public static XLoadingDialog with(Context context){
+ if (dialog==null){
+ dialog=new XLoadingDialog(context);
+ }
+ return dialog;
+ }
+
+ @Override
+ public void dismiss() {
+ super.dismiss();
+ if (dialog!=null)
+ dialog=null;
+ }
+
+ public XLoadingDialog setCanceled(boolean cancel) {
+ setCanceledOnTouchOutside(cancel);
+ setCancelable(cancel);
+ return dialog;
+ }
+
+ public XLoadingDialog setMessage(String message) {
+ if (xTextView != null && !TextUtils.isEmpty(message)) {
+ xTextView.setText(message);
+ }
+ return this;
+ }
+}
diff --git a/xframe/src/main/java/com/youth/xframe/widget/XLoadingView.java b/xframe/src/main/java/com/youth/xframe/widget/XLoadingView.java
new file mode 100644
index 0000000..a491fc9
--- /dev/null
+++ b/xframe/src/main/java/com/youth/xframe/widget/XLoadingView.java
@@ -0,0 +1,147 @@
+package com.youth.xframe.widget;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v4.app.Fragment;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.youth.xframe.R;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 简单实用的页面状态统一管理 ,加载中、无网络、无数据、出错等状态的随意切换
+ */
+public class XLoadingView extends FrameLayout {
+
+ private int mEmptyViewResId;
+ private int mErrorViewResId;
+ private int mLoadingViewResId;
+ private int mNoNetworkViewResId;
+ private int mContentViewResId;
+ private LayoutInflater mInflater;
+ private OnClickListener mOnRetryClickListener;
+ private Map mResId = new HashMap<>();
+
+ public static XLoadingView wrap(Activity activity) {
+ return wrap(((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0));
+ }
+
+ public static XLoadingView wrap(Fragment fragment) {
+ return wrap(fragment.getView());
+ }
+
+ public static XLoadingView wrap(View view) {
+ if (view == null) {
+ throw new RuntimeException("content view can not be null");
+ }
+ ViewGroup parent = (ViewGroup) view.getParent();
+ if (view == null) {
+ throw new RuntimeException("parent view can not be null");
+ }
+ ViewGroup.LayoutParams lp = view.getLayoutParams();
+ int index = parent.indexOfChild(view);
+ parent.removeView(view);
+
+ XLoadingView xLoadingView = new XLoadingView(view.getContext());
+ parent.addView(xLoadingView, index, lp);
+ xLoadingView.addView(view);
+ xLoadingView.setContentView(view);
+ return xLoadingView;
+ }
+
+ public XLoadingView(Context context) {
+ this(context, null);
+ }
+
+ public XLoadingView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public XLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mInflater = LayoutInflater.from(context);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.XLoadingView, defStyleAttr, 0);
+ mEmptyViewResId = a.getResourceId(R.styleable.XLoadingView_emptyView, R.layout.xloading_empty_view);
+ mErrorViewResId = a.getResourceId(R.styleable.XLoadingView_errorView, R.layout.xloading_error_view);
+ mLoadingViewResId = a.getResourceId(R.styleable.XLoadingView_loadingView, R.layout.xloading_loading_view);
+ mNoNetworkViewResId = a.getResourceId(R.styleable.XLoadingView_noNetworkView, R.layout.xloading_no_network_view);
+ a.recycle();
+ }
+
+ private void setContentView(View view) {
+ mContentViewResId = view.getId();
+ mResId.put(mContentViewResId, view);
+ }
+
+ public final void showEmpty() {
+ show(mEmptyViewResId);
+ }
+
+ public final void showError() {
+ show(mErrorViewResId);
+ }
+
+ public final void showLoading() {
+ show(mLoadingViewResId);
+ }
+
+ public final void showNoNetwork() {
+ show(mNoNetworkViewResId);
+ }
+
+ public final void showContent() {
+ show(mContentViewResId);
+ }
+
+ private void show(int resId) {
+ for (View view : mResId.values()) {
+ view.setVisibility(GONE);
+ }
+ layout(resId).setVisibility(VISIBLE);
+ }
+
+ private View layout(int resId) {
+ if (mResId.containsKey(resId)) {
+ return mResId.get(resId);
+ }
+ View view = mInflater.inflate(resId, this, false);
+ view.setVisibility(GONE);
+ addView(view);
+ mResId.put(resId, view);
+ if (resId == mErrorViewResId||resId == mNoNetworkViewResId) {
+ View v=view.findViewById(R.id.xloading_retry);
+ if (mOnRetryClickListener != null && v != null) {
+ v.setOnClickListener(mOnRetryClickListener);
+ }
+ }
+ return view;
+ }
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ if (getChildCount() == 0) {
+ return;
+ }
+ if (getChildCount() > 1) {
+ removeViews(1, getChildCount() - 1);
+ }
+ View view = getChildAt(0);
+ setContentView(view);
+ showLoading();
+ }
+ /**
+ * 设置重试点击事件
+ *
+ * @param onRetryClickListener 重试点击事件
+ */
+ public void setOnRetryClickListener(OnClickListener onRetryClickListener) {
+ this.mOnRetryClickListener = onRetryClickListener;
+ }
+}
diff --git a/xframe/src/main/java/com/youth/xframe/widget/XSplashView.java b/xframe/src/main/java/com/youth/xframe/widget/XSplashView.java
new file mode 100644
index 0000000..46f4505
--- /dev/null
+++ b/xframe/src/main/java/com/youth/xframe/widget/XSplashView.java
@@ -0,0 +1,360 @@
+package com.youth.xframe.widget;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.shapes.Shape;
+import android.os.Build;
+import android.os.Handler;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.youth.xframe.XFrame;
+import com.youth.xframe.utils.XPreferencesUtils;
+import com.youth.xframe.utils.handler.XHandler;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ 闪屏页或者广告页:
+ 在合适的时机显示 SplashView - 可控性
+ 下载、缓存、更新图片
+ 回调响应图片点击事件
+ 倒计时 Dismiss View,主动跳过 Dissmiss View
+ 本地没有缓存时,显示默认图片或者不显示 SplashView
+ */
+public class XSplashView extends FrameLayout {
+
+ ImageView splashImageView;
+ TextView skipButton;
+
+ private static final String IMG_URL = "X_SPLASH_IMG_URL";
+ private static final String ACT_URL = "X_SPLASH_ACT_URL";
+ private static String IMG_PATH = null;
+ private static final int skipButtonSizeInDip = 36;
+ private static final int skipButtonMarginInDip = 16;
+ private Integer duration = 6;
+ private static final int delayTime = 1000; // 每隔1000 毫秒执行一次
+
+ private String imgUrl = null;
+ private String actUrl = null;
+
+ private boolean isActionBarShowing = true;
+
+ private Activity mActivity = null;
+
+ private OnSplashViewActionListener mOnSplashViewActionListener = null;
+
+ private XHandler handler = new XHandler();
+ private Runnable timerRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (0 == duration) {
+ dismissSplashView(false);
+ return;
+ } else {
+ setDuration(--duration);
+ }
+ handler.postDelayed(timerRunnable, delayTime);
+ }
+ };
+
+ private void setImage(Bitmap image) {
+ splashImageView.setImageBitmap(image);
+ }
+
+ public XSplashView(Activity context) {
+ super(context);
+ mActivity = context;
+ initComponents();
+ }
+
+ public XSplashView(Activity context, AttributeSet attrs) {
+ super(context, attrs);
+ mActivity = context;
+ initComponents();
+ }
+
+ public XSplashView(Activity context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mActivity = context;
+ initComponents();
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public XSplashView(Activity context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ mActivity = context;
+ initComponents();
+ }
+
+ private GradientDrawable splashSkipButtonBg = new GradientDrawable();
+
+ void initComponents() {
+ splashSkipButtonBg.setShape(GradientDrawable.OVAL);
+ splashSkipButtonBg.setColor(Color.parseColor("#66333333"));
+
+ splashImageView = new ImageView(mActivity);
+ splashImageView.setScaleType(ImageView.ScaleType.FIT_XY);
+ splashImageView.setBackgroundColor(mActivity.getResources().getColor(android.R.color.white));
+ LayoutParams imageViewLayoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ this.addView(splashImageView, imageViewLayoutParams);
+ splashImageView.setClickable(true);
+
+ skipButton = new TextView(mActivity);
+ int skipButtonSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, skipButtonSizeInDip, mActivity.getResources().getDisplayMetrics());
+ LayoutParams skipButtonLayoutParams = new LayoutParams(skipButtonSize, skipButtonSize);
+ skipButtonLayoutParams.gravity = Gravity.TOP|Gravity.RIGHT;
+ int skipButtonMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, skipButtonMarginInDip, mActivity.getResources().getDisplayMetrics());
+ skipButtonLayoutParams.setMargins(0, skipButtonMargin, skipButtonMargin, 0);
+ skipButton.setGravity(Gravity.CENTER);
+ skipButton.setTextColor(mActivity.getResources().getColor(android.R.color.white));
+ skipButton.setBackgroundDrawable(splashSkipButtonBg);
+ skipButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10);
+ this.addView(skipButton, skipButtonLayoutParams);
+
+ skipButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dismissSplashView(true);
+ }
+ });
+
+ setDuration(duration);
+ handler.postDelayed(timerRunnable, delayTime);
+ }
+
+ private void setImgUrl(String imgUrl) {
+ this.imgUrl = imgUrl;
+ }
+
+ private void setActUrl(String actUrl) {
+ this.actUrl = actUrl;
+ }
+
+ private void setDuration(Integer duration) {
+ this.duration = duration;
+ skipButton.setText(String.format("跳过\n%d s", duration));
+ }
+
+ private void setOnSplashImageClickListener(@Nullable final OnSplashViewActionListener listener) {
+ if (null == listener) return;
+ mOnSplashViewActionListener = listener;
+ splashImageView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ listener.onSplashImageClick(actUrl);
+ }
+ });
+ }
+
+ /**
+ * static method, show splashView on above of the activity
+ * you should called after setContentView()
+ * @param activity activity instance
+ * @param durationTime time to countDown
+ * @param defaultBitmapRes if there's no cached bitmap, show this default bitmap;
+ * if null == defaultBitmapRes, then will not show the splashView
+ * @param listener splash view listener contains onImageClick and onDismiss
+ */
+ public static void showSplashView(@NonNull Activity activity,
+ @Nullable Integer durationTime,
+ @Nullable Integer defaultBitmapRes,
+ @Nullable OnSplashViewActionListener listener) {
+
+ ViewGroup contentView = (ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content);
+ if (null == contentView || 0 == contentView.getChildCount()) {
+ throw new IllegalStateException("You should call showSplashView() after setContentView() in Activity instance");
+ }
+ IMG_PATH = activity.getFilesDir().getAbsolutePath().toString() + "/splash_img.jpg";
+ XSplashView splashView = new XSplashView(activity);
+ RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ splashView.setOnSplashImageClickListener(listener);
+ if (null != durationTime) splashView.setDuration(durationTime);
+ Bitmap bitmapToShow = null;
+ String imgUrl=(String)XPreferencesUtils.get(IMG_URL, null);
+ if (!TextUtils.isEmpty(imgUrl) && isFileExist(IMG_PATH)) {
+ bitmapToShow = BitmapFactory.decodeFile(IMG_PATH);
+ splashView.setImgUrl(imgUrl);
+ splashView.setActUrl((String)XPreferencesUtils.get(ACT_URL, null));
+ } else if (null != defaultBitmapRes) {
+ bitmapToShow = BitmapFactory.decodeResource(activity.getResources(), defaultBitmapRes);
+ }
+
+ if (null == bitmapToShow) return;
+ splashView.setImage(bitmapToShow);
+ activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ if (activity instanceof AppCompatActivity) {
+ ActionBar supportActionBar = ((AppCompatActivity) activity).getSupportActionBar();
+ if (null != supportActionBar) {
+ supportActionBar.setShowHideAnimationEnabled(false);
+ splashView.isActionBarShowing = supportActionBar.isShowing();
+ supportActionBar.hide();
+ }
+ } else if (activity instanceof Activity) {
+ android.app.ActionBar actionBar = activity.getActionBar();
+ if (null != actionBar) {
+ splashView.isActionBarShowing = actionBar.isShowing();
+ actionBar.hide();
+ }
+ }
+ contentView.addView(splashView, param);
+ }
+
+ /**
+ * simple way to show splash view, set all non-able param as non
+ * @param activity
+ */
+ public static void simpleShowSplashView(@NonNull Activity activity) {
+ showSplashView(activity, null, null, null);
+ }
+
+ private void dismissSplashView(boolean initiativeDismiss) {
+ if (null != mOnSplashViewActionListener) mOnSplashViewActionListener.onSplashViewDismiss(initiativeDismiss);
+
+
+ handler.removeCallbacks(timerRunnable);
+ final ViewGroup parent = (ViewGroup) this.getParent();
+ if (null != parent) {
+ ObjectAnimator animator = ObjectAnimator.ofFloat(XSplashView.this, "scale", 0.0f, 0.5f).setDuration(600);
+ animator.start();
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float cVal = (Float) animation.getAnimatedValue();
+ XSplashView.this.setAlpha(1.0f - 2.0f * cVal);
+ XSplashView.this.setScaleX(1.0f + cVal);
+ XSplashView.this.setScaleY(1.0f + cVal);
+ }
+ });
+ animator.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ parent.removeView(XSplashView.this);
+ showSystemUi();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ parent.removeView(XSplashView.this);
+ showSystemUi();
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
+ });
+ }
+ }
+
+ private void showSystemUi() {
+ mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ if (mActivity instanceof AppCompatActivity) {
+ ActionBar supportActionBar = ((AppCompatActivity) mActivity).getSupportActionBar();
+ if (null != supportActionBar) {
+ if (isActionBarShowing) supportActionBar.show();
+ }
+ } else if (mActivity instanceof Activity) {
+ android.app.ActionBar actionBar = mActivity.getActionBar();
+ if (null != actionBar) {
+ if (isActionBarShowing) actionBar.show();
+ }
+ }
+ }
+
+
+ /**
+ * static method, update splash view data
+ * @param imgUrl - url of image which you want to set as splash image
+ * @param actionUrl - related action url, such as webView etc.
+ */
+ public static void updateSplashData(@NonNull Activity activity, @NonNull String imgUrl, @Nullable String actionUrl) {
+ IMG_PATH = activity.getFilesDir().getAbsolutePath().toString() + "/splash_img.jpg";
+
+ XPreferencesUtils.put(IMG_URL, imgUrl);
+ XPreferencesUtils.put(ACT_URL, actionUrl);
+
+ getAndSaveNetWorkBitmap(imgUrl);
+ }
+
+ public interface OnSplashViewActionListener {
+ void onSplashImageClick(String actionUrl);
+ void onSplashViewDismiss(boolean initiativeDismiss);
+ }
+
+ private static void getAndSaveNetWorkBitmap(final String urlString) {
+ Runnable getAndSaveImageRunnable = new Runnable() {
+ @Override
+ public void run() {
+ URL imgUrl = null;
+ Bitmap bitmap = null;
+ try {
+ imgUrl = new URL(urlString);
+ HttpURLConnection urlConn = (HttpURLConnection) imgUrl.openConnection();
+ urlConn.setDoInput(true);
+ urlConn.connect();
+ InputStream is = urlConn.getInputStream();
+ bitmap = BitmapFactory.decodeStream(is);
+ is.close();
+ saveBitmapFile(bitmap, IMG_PATH);
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ new Thread(getAndSaveImageRunnable).start();
+ }
+
+ private static void saveBitmapFile(Bitmap bm, String filePath) throws IOException {
+ File myCaptureFile = new File(filePath);
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));
+ bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);
+ bos.flush();
+ bos.close();
+ }
+
+ public static boolean isFileExist(String filePath) {
+ if(TextUtils.isEmpty(filePath)) {
+ return false;
+ } else {
+ File file = new File(filePath);
+ return file.exists() && file.isFile();
+ }
+ }
+}
diff --git a/xframe/src/main/java/com/youth/xframe/widget/XToast.java b/xframe/src/main/java/com/youth/xframe/widget/XToast.java
new file mode 100644
index 0000000..f12ae25
--- /dev/null
+++ b/xframe/src/main/java/com/youth/xframe/widget/XToast.java
@@ -0,0 +1,178 @@
+package com.youth.xframe.widget;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.CheckResult;
+import android.support.annotation.ColorInt;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.youth.xframe.R;
+import com.youth.xframe.XFrame;
+import com.youth.xframe.utils.XOutdatedUtils;
+
+/**
+ * Toast
+ */
+public class XToast {
+ private static final @ColorInt int DEFAULT_TEXT_COLOR = Color.parseColor("#FFFFFF");
+
+ private static final @ColorInt int ERROR_COLOR = Color.parseColor("#D8524E");
+ private static final @ColorInt int INFO_COLOR = Color.parseColor("#3278B5");
+ private static final @ColorInt int SUCCESS_COLOR = Color.parseColor("#5BB75B");
+ private static final @ColorInt int WARNING_COLOR = Color.parseColor("#FB9B4D");
+ private static final @ColorInt int NORMAL_COLOR = Color.parseColor("#444344");
+
+ private static final String TOAST_TYPEFACE = "sans-serif-condensed";
+
+ private static Context context= XFrame.getContext();
+
+ private XToast() {
+ }
+
+ public static @CheckResult Toast normal( @NonNull String message) {
+ return normal( message, Toast.LENGTH_SHORT, null);
+ }
+
+ public static @CheckResult Toast normal( @NonNull String message, Drawable icon) {
+ return normal( message, Toast.LENGTH_SHORT, icon);
+ }
+
+ public static @CheckResult Toast normal( @NonNull String message, int duration) {
+ return normal( message, duration);
+ }
+
+ public static @CheckResult Toast normal( @NonNull String message, int duration,
+ Drawable icon) {
+ return custom( message, icon ,NORMAL_COLOR, duration);
+ }
+
+ public static @CheckResult Toast warning( @NonNull String message) {
+ return warning( message, Toast.LENGTH_SHORT, true);
+ }
+
+ public static @CheckResult Toast warning( @NonNull String message, int duration) {
+ return warning( message, duration, true);
+ }
+
+ public static @CheckResult Toast warning( @NonNull String message, int duration, boolean withIcon) {
+ Drawable icon=null;
+ if (withIcon){
+ icon=XOutdatedUtils.getDrawable( R.drawable.xtoast_warning);
+ }
+ return custom( message,icon, WARNING_COLOR, duration);
+ }
+
+ public static @CheckResult Toast info( @NonNull String message) {
+ return info( message, Toast.LENGTH_SHORT, true);
+ }
+
+ public static @CheckResult Toast info( @NonNull String message, int duration) {
+ return info( message, duration, true);
+ }
+
+ public static @CheckResult Toast info( @NonNull String message, int duration, boolean withIcon) {
+ Drawable icon=null;
+ if (withIcon){
+ icon=XOutdatedUtils.getDrawable( R.drawable.xtoast_info);
+ }
+ return custom( message,icon, INFO_COLOR, duration);
+ }
+
+ public static @CheckResult Toast success( @NonNull String message) {
+ return success( message, Toast.LENGTH_SHORT, true);
+ }
+
+ public static @CheckResult Toast success( @NonNull String message, int duration) {
+ return success( message, duration, true);
+ }
+
+ public static @CheckResult Toast success( @NonNull String message, int duration, boolean withIcon) {
+ Drawable icon=null;
+ if (withIcon){
+ icon=XOutdatedUtils.getDrawable( R.drawable.xtoast_success);
+ }
+ return custom( message,icon, SUCCESS_COLOR, duration);
+ }
+
+ public static @CheckResult Toast error( @NonNull String message) {
+ return error( message, Toast.LENGTH_SHORT, true);
+ }
+
+ public static @CheckResult Toast error( @NonNull String message, int duration) {
+ return error( message, duration, true);
+ }
+
+ public static @CheckResult Toast error( @NonNull String message, int duration, boolean withIcon) {
+ Drawable icon=null;
+ if (withIcon){
+ icon=XOutdatedUtils.getDrawable( R.drawable.xtoast_error);
+ }
+ return custom( message,icon, ERROR_COLOR, duration);
+ }
+
+ public static @CheckResult Toast custom(@NonNull String message, @ColorInt int tintColor) {
+ return custom( message, null, DEFAULT_TEXT_COLOR, tintColor,Toast.LENGTH_SHORT);
+ }
+
+ public static @CheckResult Toast custom( @NonNull String message, Drawable icon, @ColorInt int tintColor) {
+ return custom( message, icon, DEFAULT_TEXT_COLOR, tintColor,Toast.LENGTH_SHORT);
+ }
+
+ public static @CheckResult Toast custom(@NonNull String message, @ColorInt int tintColor,int duration) {
+ return custom( message, null, DEFAULT_TEXT_COLOR, tintColor,duration);
+ }
+
+ public static @CheckResult Toast custom( @NonNull String message, Drawable icon, @ColorInt int tintColor,int duration) {
+ return custom( message, icon, DEFAULT_TEXT_COLOR, tintColor,duration);
+ }
+ public static @CheckResult Toast custom( @NonNull String message, @DrawableRes int iconRes,
+ @ColorInt int textColor, @ColorInt int tintColor, int duration) {
+ return custom( message, XOutdatedUtils.getDrawable( iconRes), textColor,tintColor, duration);
+ }
+
+ /**
+ * 自定义toast方法
+ * @param message 提示消息文本
+ * @param icon 提示消息的icon,传入null代表不显示
+ * @param textColor 提示消息文本颜色
+ * @param tintColor 提示背景颜色
+ * @param duration 显示时长
+ * @return
+ */
+ public static @CheckResult Toast custom( @NonNull String message, Drawable icon,
+ @ColorInt int textColor, @ColorInt int tintColor, int duration) {
+ Toast currentToast = new Toast(context);
+ View toastLayout = LayoutInflater.from(context).inflate(R.layout.xtoast_view, null);
+ ImageView toastIcon = (ImageView) toastLayout.findViewById(R.id.xtoast_icon);
+ TextView toastText = (TextView) toastLayout.findViewById(R.id.xtoast_text);
+
+ Drawable drawableFrame= XOutdatedUtils.getDrawable(R.drawable.xtoast_frame);
+ drawableFrame.setColorFilter(new PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_IN));
+ XOutdatedUtils.setBackground(toastLayout, drawableFrame);
+
+ if (icon == null){
+ toastIcon.setVisibility(View.GONE);
+ }else{
+ XOutdatedUtils.setBackground(toastIcon, icon);
+ }
+
+ toastText.setTextColor(textColor);
+ toastText.setText(message);
+ toastText.setTypeface(Typeface.create(TOAST_TYPEFACE, Typeface.NORMAL));
+
+ currentToast.setView(toastLayout);
+ currentToast.setDuration(duration);
+ currentToast.show();
+ return currentToast;
+ }
+}
diff --git a/xframe/src/main/res/drawable-xhdpi/adapter_loading_error.png b/xframe/src/main/res/drawable-xhdpi/adapter_loading_error.png
new file mode 100644
index 0000000..8b0c4a5
Binary files /dev/null and b/xframe/src/main/res/drawable-xhdpi/adapter_loading_error.png differ
diff --git a/xframe/src/main/res/drawable-xhdpi/adapter_loading_no_data.png b/xframe/src/main/res/drawable-xhdpi/adapter_loading_no_data.png
new file mode 100644
index 0000000..d71091a
Binary files /dev/null and b/xframe/src/main/res/drawable-xhdpi/adapter_loading_no_data.png differ
diff --git a/xframe/src/main/res/drawable-xhdpi/xloading_empty.png b/xframe/src/main/res/drawable-xhdpi/xloading_empty.png
new file mode 100644
index 0000000..f7d8fac
Binary files /dev/null and b/xframe/src/main/res/drawable-xhdpi/xloading_empty.png differ
diff --git a/xframe/src/main/res/drawable-xhdpi/xloading_error.png b/xframe/src/main/res/drawable-xhdpi/xloading_error.png
new file mode 100644
index 0000000..80da690
Binary files /dev/null and b/xframe/src/main/res/drawable-xhdpi/xloading_error.png differ
diff --git a/xframe/src/main/res/drawable-xhdpi/xloading_no_network.png b/xframe/src/main/res/drawable-xhdpi/xloading_no_network.png
new file mode 100644
index 0000000..5c1951a
Binary files /dev/null and b/xframe/src/main/res/drawable-xhdpi/xloading_no_network.png differ
diff --git a/xframe/src/main/res/drawable-xhdpi/xtoast_error.png b/xframe/src/main/res/drawable-xhdpi/xtoast_error.png
new file mode 100644
index 0000000..3964192
Binary files /dev/null and b/xframe/src/main/res/drawable-xhdpi/xtoast_error.png differ
diff --git a/xframe/src/main/res/drawable-xhdpi/xtoast_frame.9.png b/xframe/src/main/res/drawable-xhdpi/xtoast_frame.9.png
new file mode 100644
index 0000000..77e69c7
Binary files /dev/null and b/xframe/src/main/res/drawable-xhdpi/xtoast_frame.9.png differ
diff --git a/xframe/src/main/res/drawable-xhdpi/xtoast_info.png b/xframe/src/main/res/drawable-xhdpi/xtoast_info.png
new file mode 100644
index 0000000..3a82cab
Binary files /dev/null and b/xframe/src/main/res/drawable-xhdpi/xtoast_info.png differ
diff --git a/xframe/src/main/res/drawable-xhdpi/xtoast_success.png b/xframe/src/main/res/drawable-xhdpi/xtoast_success.png
new file mode 100644
index 0000000..d670618
Binary files /dev/null and b/xframe/src/main/res/drawable-xhdpi/xtoast_success.png differ
diff --git a/xframe/src/main/res/drawable-xhdpi/xtoast_warning.png b/xframe/src/main/res/drawable-xhdpi/xtoast_warning.png
new file mode 100644
index 0000000..b144939
Binary files /dev/null and b/xframe/src/main/res/drawable-xhdpi/xtoast_warning.png differ
diff --git a/xframe/src/main/res/drawable/loading_dialog_bg.xml b/xframe/src/main/res/drawable/loading_dialog_bg.xml
new file mode 100644
index 0000000..2c9c03f
--- /dev/null
+++ b/xframe/src/main/res/drawable/loading_dialog_bg.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xframe/src/main/res/drawable/xloading_btn_selector.xml b/xframe/src/main/res/drawable/xloading_btn_selector.xml
new file mode 100644
index 0000000..86078f4
--- /dev/null
+++ b/xframe/src/main/res/drawable/xloading_btn_selector.xml
@@ -0,0 +1,20 @@
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xframe/src/main/res/layout/adapter_loading.xml b/xframe/src/main/res/layout/adapter_loading.xml
new file mode 100644
index 0000000..e5ab3f7
--- /dev/null
+++ b/xframe/src/main/res/layout/adapter_loading.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xframe/src/main/res/layout/adapter_loading_failed.xml b/xframe/src/main/res/layout/adapter_loading_failed.xml
new file mode 100644
index 0000000..9ed7995
--- /dev/null
+++ b/xframe/src/main/res/layout/adapter_loading_failed.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xframe/src/main/res/layout/adapter_no_more.xml b/xframe/src/main/res/layout/adapter_no_more.xml
new file mode 100644
index 0000000..d6986fd
--- /dev/null
+++ b/xframe/src/main/res/layout/adapter_no_more.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xframe/src/main/res/layout/xloading_dialog.xml b/xframe/src/main/res/layout/xloading_dialog.xml
new file mode 100644
index 0000000..00c3b53
--- /dev/null
+++ b/xframe/src/main/res/layout/xloading_dialog.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
diff --git a/xframe/src/main/res/layout/xloading_empty_view.xml b/xframe/src/main/res/layout/xloading_empty_view.xml
new file mode 100644
index 0000000..e52122d
--- /dev/null
+++ b/xframe/src/main/res/layout/xloading_empty_view.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/xframe/src/main/res/layout/xloading_error_view.xml b/xframe/src/main/res/layout/xloading_error_view.xml
new file mode 100644
index 0000000..d5312cb
--- /dev/null
+++ b/xframe/src/main/res/layout/xloading_error_view.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xframe/src/main/res/layout/xloading_loading_view.xml b/xframe/src/main/res/layout/xloading_loading_view.xml
new file mode 100644
index 0000000..bad8955
--- /dev/null
+++ b/xframe/src/main/res/layout/xloading_loading_view.xml
@@ -0,0 +1,11 @@
+
+
+
+
\ No newline at end of file
diff --git a/xframe/src/main/res/layout/xloading_no_network_view.xml b/xframe/src/main/res/layout/xloading_no_network_view.xml
new file mode 100644
index 0000000..553631f
--- /dev/null
+++ b/xframe/src/main/res/layout/xloading_no_network_view.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xframe/src/main/res/layout/xtoast_view.xml b/xframe/src/main/res/layout/xtoast_view.xml
new file mode 100644
index 0000000..d4b59a6
--- /dev/null
+++ b/xframe/src/main/res/layout/xtoast_view.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xframe/src/main/res/values/attrs.xml b/xframe/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..74e9271
--- /dev/null
+++ b/xframe/src/main/res/values/attrs.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xframe/src/main/res/values/colors.xml b/xframe/src/main/res/values/colors.xml
new file mode 100644
index 0000000..1e20782
--- /dev/null
+++ b/xframe/src/main/res/values/colors.xml
@@ -0,0 +1,9 @@
+
+
+ #aaaaaa
+ #ffffff
+ #8a8a8a
+
+ @color/XFrame_white
+ #595959
+
diff --git a/xframe/src/main/res/values/dimens.xml b/xframe/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..6bb2b64
--- /dev/null
+++ b/xframe/src/main/res/values/dimens.xml
@@ -0,0 +1,13 @@
+
+ 8dp
+ 10dp
+ 16dp
+
+ 13sp
+ 15sp
+
+ 24dp
+ 24dp
+ 6dp
+
+
diff --git a/xframe/src/main/res/values/ids.xml b/xframe/src/main/res/values/ids.xml
new file mode 100644
index 0000000..3ea04e7
--- /dev/null
+++ b/xframe/src/main/res/values/ids.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/xframe/src/main/res/values/strings.xml b/xframe/src/main/res/values/strings.xml
new file mode 100644
index 0000000..f4f002b
--- /dev/null
+++ b/xframe/src/main/res/values/strings.xml
@@ -0,0 +1,8 @@
+
+ XFrame
+ 努力加载中...
+ 无网络连接,请检查你的网络
+ 加载失败,请稍后再试
+ 暂无数据
+ 点击重试
+
diff --git a/xframe/src/main/res/values/styles.xml b/xframe/src/main/res/values/styles.xml
new file mode 100644
index 0000000..6f5f7b9
--- /dev/null
+++ b/xframe/src/main/res/values/styles.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/xframe/src/test/java/com/youth/xframe/ExampleUnitTest.java b/xframe/src/test/java/com/youth/xframe/ExampleUnitTest.java
new file mode 100644
index 0000000..598a866
--- /dev/null
+++ b/xframe/src/test/java/com/youth/xframe/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.youth.xframe;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file