感谢开源,感谢大神,才让我们这些菜鸟成长!

附上云阅开源项目地址:点我吧。

1.轮播图的实现。

  现在的APP基本都会实现这个功能吧,然后一直都找不到好的第三方库,能够满足各种需求。然而碰到了这个开源库...

2.MVVM-DataBinding架构开发。

  它本质上就是MVC、MVP的改进版。实现数据和视图相互绑定。MVVM就是讲其中的View的状态和行为抽象化,让我们将视图UI和业务逻辑分开。

  • gradle配置:    (在module的build.gradle中的android模块中加入如下代码块) 
 dataBinding {
enabled = true
}

3.解决Bug:Android点击应用图标后会重新进入启动页。

4.第三方库Glide的简单使用。

  • gradle配置:
implementation 'com.github.bumptech.glide:glide:4.7.1'
implementation 'jp.wasabeef:glide-transformations:2.0.1

  

5.分包策略,解决65535方法限制的问题。

  • gradle配置:
 implementation 'com.android.support:multidex:1.0.3'

6.避免在1s中多次点击按钮。

  方法:自己新建一个抽象类,集成OnClickListener,重写里面的onClick函数。

public abstract class PerfectClickListener implements OnClickListener {
public static final int MIN_CLICK_DELAY_TIME = 1000;
private long lastClickTime = 0;
private int id = -1; @Override
public void onClick(View v) {
long currentTime = Calendar.getInstance().getTimeInMillis();
int mId = v.getId();
if (id != mId) {
id = mId;
lastClickTime = currentTime;
onNoDoubleClick(v);
return;
}
if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) {
lastClickTime = currentTime;
onNoDoubleClick(v);
}
} protected abstract void onNoDoubleClick(View v);
}

  使用场景:在启动页中,有一个跳转按钮,避免用户多次点击启动多个主页。

7.如何使用android.support.v7.widget.Toolbar

  • 首先一定要在build.gradle中添加依赖。
 implementation "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion"
implementation "com.android.support:design:$rootProject.supportLibraryVersion"
implementation "com.android.support:support-v4:$rootProject.supportLibraryVersion"
implementation "com.android.support:cardview-v7:$rootProject.supportLibraryVersion"

  这里使用了rootProject来间接设置,注意这个rootProject要在项目的build.gradle中具体配置。具体百度吧。

  • 然后再布局中这样用。
 <android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorTheme"
app:contentInsetStart="0.0dp"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ToolbarStyle">

  这里使用了自定义主题,在style文件中自己创建一个。

8.设置主题点击波纹效果。

  • 首先得引入谷歌的材料设计库,上面第7点中有相关引入方式。
  • 然后再布局文件中:android:background="?attr/...."   (这里省略号写一些波纹样式即可)
  • 参考文章:https://yq.aliyun.com/articles/12407

9.左右滑动ViewPager时,没获取焦点没响应。

  原来仅仅是在定义Viewpager的时候,添加如下代码即可。

android:descendantFocusability="blocksDescendants"
      beforeDescendants:viewgroup会优先其子类控件而获取到焦点

        afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点

        blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点

10.设置状态栏颜色以及其他方法。

  • 首先自定义一个视图叫做StatusBarView。
public class StatusBarView extends View {
public StatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
} public StatusBarView(Context context) {
super(context);
}
}
  • 然后写一个通用类,统一设置状态栏的一些属性。
public class StatusBarUtil {

    public static final int DEFAULT_STATUS_BAR_ALPHA = 112;

    /**
* 设置状态栏颜色
*
* @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 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;
}
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(color);
} else {
StatusBarView statusView = createStatusBarView(activity, color);
decorView.addView(statusView);
}
setRootView(activity);
} /**
* 使状态栏半透明
* <p>
* 适用于图片作为背景的界面,此时需要图片填充到状态栏
*
* @param activity 需要设置的activity
*/
public static void setTranslucent(Activity activity) {
setTranslucent(activity, DEFAULT_STATUS_BAR_ALPHA);
} /**
* 使状态栏半透明
* <p>
* 适用于图片作为背景的界面,此时需要图片填充到状态栏
*
* @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, 使状态栏半透明
* <p>
* 适用于图片作为背景的界面,此时需要图片填充到状态栏
*
* @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以上半透明效果,不建议使用)
* <p>
* 适用于图片作为背景的界面,此时需要图片填充到状态栏
*
* @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(calculateStatusColor(color, statusBarAlpha));
} 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());
}
// 设置属性
ViewGroup drawer = (ViewGroup) drawerLayout.getChildAt(1);
drawerLayout.setFitsSystemWindows(false);
contentLayout.setFitsSystemWindows(false);
contentLayout.setClipToPadding(true);
drawer.setFitsSystemWindows(false); addTranslucentView(activity, statusBarAlpha);
} /**
* 为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);
}
// 设置属性
ViewGroup drawer = (ViewGroup) drawerLayout.getChildAt(1);
drawerLayout.setFitsSystemWindows(false);
contentLayout.setFitsSystemWindows(false);
contentLayout.setClipToPadding(true);
drawer.setFitsSystemWindows(false);
}
} /**
* 为 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);
} // 设置属性
ViewGroup drawer = (ViewGroup) drawerLayout.getChildAt(1);
drawerLayout.setFitsSystemWindows(false);
contentLayout.setFitsSystemWindows(false);
contentLayout.setClipToPadding(true);
drawer.setFitsSystemWindows(false);
} /**
* 为 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;
}
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);
if (activity instanceof TabActivity){
activity.getWindow()//兼容TabActivity
.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
} else {
activity.getWindow()
.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
addTranslucentView(activity, statusBarAlpha);
if (needOffsetView != null) {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) needOffsetView.getLayoutParams();
if (layoutParams != null) {
layoutParams.setMargins(0, getStatusBarHeight(activity), 0, 0);
}
}
} public static void setMargin(Activity activity, View needOffsetView) {
if (needOffsetView != null) {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) needOffsetView.getLayoutParams();
if (layoutParams != null) {
layoutParams.setMargins(0, getStatusBarHeight(activity), 0, 0);
}
}
} /**
* 为 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 rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
rootView.setFitsSystemWindows(true);
rootView.setClipToPadding(true);
} /**
* 使状态栏透明
*/
@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 状态栏高度
*/
public 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;
} }
  • 简单用法:根据自己需求在需要的地方,StatusBarUtil.set相关的方法即可。

11.常见的item点击的效果样式文件。

  长按或者点击一个TextView之后,背景颜色更改,一般都是初始为白色,长按后显示灰色。颜色值也是很讲究的。

  有点类似微信页面每一个item点击的效果,一直调不出那样的效果。主要是找不到合适的颜色。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false">
<shape>
<solid android:color="#F1F3F4" />
</shape>
</item>
<item android:state_pressed="true">
<shape>
<solid android:color="#d9d9d9" />
</shape>
</item>
<item android:state_pressed="false">
<shape>
<solid android:color="#F1F3F4" />
</shape>
</item> </selector>

12.用SharePerferences文件来记录全局配置。

  可以写一个通用类,用来封装不同数据类型写入文件,从文件中获取数据的方法。

public class SPUtils {

    private static final String CONFIG = "config";

    /**
* 获取SharedPreferences实例对象
*
* @param fileName
*/
private static SharedPreferences getSharedPreference(String fileName) {
return MyApplication.getInstance().getSharedPreferences(fileName, Context.MODE_PRIVATE);
} /**
* 保存一个String类型的值!
*/
public static void putString(String key, String value) {
SharedPreferences.Editor editor = getSharedPreference(CONFIG).edit();
editor.putString(key, value).apply();
} /**
* 获取String的value
*/
public static String getString(String key, String defValue) {
SharedPreferences sharedPreference = getSharedPreference(CONFIG);
return sharedPreference.getString(key, defValue);
} /**
* 保存一个Boolean类型的值!
*/
public static void putBoolean(String key, Boolean value) {
SharedPreferences.Editor editor = getSharedPreference(CONFIG).edit();
editor.putBoolean(key, value).apply();
} /**
* 获取boolean的value
*/
public static boolean getBoolean(String key, Boolean defValue) {
SharedPreferences sharedPreference = getSharedPreference(CONFIG);
return sharedPreference.getBoolean(key, defValue);
} /**
* 保存一个int类型的值!
*/
public static void putInt(String key, int value) {
SharedPreferences.Editor editor = getSharedPreference(CONFIG).edit();
editor.putInt(key, value).apply();
} /**
* 获取int的value
*/
public static int getInt(String key, int defValue) {
SharedPreferences sharedPreference = getSharedPreference(CONFIG);
return sharedPreference.getInt(key, defValue);
} /**
* 保存一个float类型的值!
*/
public static void putFloat(String fileName, String key, float value) {
SharedPreferences.Editor editor = getSharedPreference(fileName).edit();
editor.putFloat(key, value).apply();
} /**
* 获取float的value
*/
public static float getFloat(String key, Float defValue) {
SharedPreferences sharedPreference = getSharedPreference(CONFIG);
return sharedPreference.getFloat(key, defValue);
} /**
* 保存一个long类型的值!
*/
public static void putLong(String key, long value) {
SharedPreferences.Editor editor = getSharedPreference(CONFIG).edit();
editor.putLong(key, value).apply();
} /**
* 获取long的value
*/
public static long getLong(String key, long defValue) {
SharedPreferences sharedPreference = getSharedPreference(CONFIG);
return sharedPreference.getLong(key, defValue);
} /**
* 取出List<String>
*
* @param key List<String> 对应的key
* @return List<String>
*/
public static List<String> getStrListValue(String key) {
List<String> strList = new ArrayList<String>();
int size = getInt(key + "size", 0);
//Log.d("sp", "" + size);
for (int i = 0; i < size; i++) {
strList.add(getString(key + i, null));
}
return strList;
} /**
* 存储List<String>
* @param key List<String>对应的key
* @param strList 对应需要存储的List<String>
*/
public static void putStrListValue(String key, List<String> strList) {
if (null == strList) {
return;
}
// 保存之前先清理已经存在的数据,保证数据的唯一性
removeStrList(key);
int size = strList.size();
putInt(key + "size", size);
for (int i = 0; i < size; i++) {
putString(key + i, strList.get(i));
}
} /**
* 清空List<String>所有数据
*
* @param key List<String>对应的key
*/
public static void removeStrList(String key) {
int size = getInt(key + "size", 0);
if (0 == size) {
return;
}
remove(key + "size");
for (int i = 0; i < size; i++) {
remove(key + i);
}
} /**
* 清空对应key数据
*/
public static void remove(String key) {
SharedPreferences.Editor editor = getSharedPreference(CONFIG).edit();
editor.remove(key).apply();
} }

  另外,可以根据自己的需求,灵活地在文件中增加一些具体的方法。比如存储APP的夜间模式或者日间模式,是否登录等。

13.利用Glide画圆角图。  

  • 首先在module的build.gradle中添加依赖,前面第4点有讲过。
  • 然后再自定义一个转换器,类似于下面这样。
public class GlideCircleTransform extends BitmapTransformation {

    public GlideCircleTransform(Context context) {
super(context);
} @Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
return circleCrop(pool, toTransform);
} private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {
if (source == null) return null;
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
// TODO this could be acquired from the pool too
Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);
Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
if (result == null) {
result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
return result;
} @Override
public String getId() {
return getClass().getName();
}
}
  • 然后就是Glide调用这个转换器了,类似于下面这样。
public static void displayCircle(ImageView imageView, String imageUrl) {
Glide.with(imageView.getContext())
.load(imageUrl)
.crossFade(500)
.error(R.drawable.ic_avatar_default)
.transform(new GlideCircleTransform(imageView.getContext()))
.into(imageView);
}

14.学会添加library。

  这里添加library不是在build.gradle中添加依赖,也不是在工程中添加libs文件。而是导入一个Module。

  其实是一个主项目需要实现某些功能,然后将这部分功能划分开来,最后将这部分功能集成到主项目中,也是是模块的划分,所以这里称为module。

  这样的好处是:可以再主module中任何地方引用子module的图片资源,代码资源等等。

  现在有一个地方不是特别理解,就是如何将多个library统一放在一个文件夹下面,这样方便管理,不然都不知道哪个是主项目了。

  添加单个library参考文章:https://blog.csdn.net/u014772414/article/details/51194952

15.学会定义BaseFragment。

  主要抓住一下要点吧。

  • 如果网络异常,则页面应该怎么显示。
  • 如果正在加载中,则页面应该怎么显示。
  • 如何动态添加自己想要的布局。

  所以在布局方面我们可以这样布局。

        <RelativeLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"> <!--加载失败-->
<LinearLayout
android:id="@+id/ll_error_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"> <ImageView
android:id="@+id/img_err"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/load_err" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="加载失败,点击重试"
android:textSize="14sp" />
</LinearLayout> <!--加载中..-->
<LinearLayout
android:id="@+id/ll_progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="80dp"
android:gravity="center_vertical"> <ImageView
android:id="@+id/img_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/yun_anim" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="努力加载中..."
android:textColor="@color/colorTabText"
android:textSize="14sp" /> </LinearLayout> </RelativeLayout>

  然后再BaseFragment中,这样决定怎么隐藏怎么显示。

public abstract class BaseFragment<SV extends ViewDataBinding> extends Fragment {

    protected SV bindingView;//布局view
protected boolean mIsVisible=false;//fragment是否显示了
private LinearLayout mLlProgressBar;//加载中
private LinearLayout mRefresh;//加载失败
protected RelativeLayout mContainer;//内容布局
private AnimationDrawable mAnimationDrawable; @Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View ll = inflater.inflate(R.layout.fragment_base, null);
bindingView = DataBindingUtil.inflate(getActivity().getLayoutInflater(),
setContent(), null, false);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
bindingView.getRoot().setLayoutParams(params);
mContainer = ll.findViewById(R.id.container);
mContainer.addView(bindingView.getRoot());//动态替换成自己想要的布局
return ll;
} @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mLlProgressBar = getView(R.id.ll_progress_bar);
ImageView img = getView(R.id.img_progress); // 加载动画
mAnimationDrawable = (AnimationDrawable) img.getDrawable();
// 默认进入页面就开启动画
if (!mAnimationDrawable.isRunning()) {
mAnimationDrawable.start();
}
mRefresh = getView(R.id.ll_error_refresh);
// 点击加载失败布局
mRefresh.setOnClickListener(new PerfectClickListener() {
@Override
protected void onNoDoubleClick(View v) {
showLoading();
onRefresh();
}
});
bindingView.getRoot().setVisibility(View.GONE); } protected <T extends View> T getView(int id) {
return (T) getView().findViewById(id);
} /**
* 加载失败后点击后的操作
*/
protected void onRefresh() { } /**
* 显示加载中状态
*/
protected void showLoading() {
if (mLlProgressBar.getVisibility() != View.VISIBLE) {
mLlProgressBar.setVisibility(View.VISIBLE);
}
// 开始动画
if (!mAnimationDrawable.isRunning()) {
mAnimationDrawable.start();
}
if (bindingView.getRoot().getVisibility() != View.GONE) {
bindingView.getRoot().setVisibility(View.GONE);
}
if (mRefresh.getVisibility() != View.GONE) {
mRefresh.setVisibility(View.GONE);
}
} /**
* 加载完成的状态
*/
protected void showContentView() {
if (mLlProgressBar.getVisibility() != View.GONE) {
mLlProgressBar.setVisibility(View.GONE);
}
// 停止动画
if (mAnimationDrawable.isRunning()) {
mAnimationDrawable.stop();
}
if (mRefresh.getVisibility() != View.GONE) {
mRefresh.setVisibility(View.GONE);
}
if (bindingView.getRoot().getVisibility() != View.VISIBLE) {
bindingView.getRoot().setVisibility(View.VISIBLE);
}
} /**
* 加载失败点击重新加载的状态
*/
protected void showError() {
if (mLlProgressBar.getVisibility() != View.GONE) {
mLlProgressBar.setVisibility(View.GONE);
}
// 停止动画
if (mAnimationDrawable.isRunning()) {
mAnimationDrawable.stop();
}
if (mRefresh.getVisibility() != View.VISIBLE) {
mRefresh.setVisibility(View.VISIBLE);
}
if (bindingView.getRoot().getVisibility() != View.GONE) {
bindingView.getRoot().setVisibility(View.GONE);
}
} /**
* 布局
*/
public abstract int setContent(); /**
* 在这里实现Fragment数据的缓加载.
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getUserVisibleHint()) {
mIsVisible = true;
loadData();
} else {
mIsVisible = false; }
} /**
* 显示时加载数据,需要这样的使用
* 注意声明 isPrepared,先初始化
* 生命周期会先执行 setUserVisibleHint 再执行onActivityCreated
* 在 onActivityCreated 之后第一次显示加载数据,只加载一次
*/
protected void loadData() {
} @Override
public void onDestroy() {
super.onDestroy();
}
}

16.ViewModel使用方法。

   implementation 'android.arch.lifecycle:extensions:1.1.0'
implementation 'android.arch.lifecycle:reactivestreams:1.1.0'

17.RxJava+RxAndroid的学习。

  作用:RxJava是一个Android中的响应式实现,RxAndroid将异步UI事件封装起来。

  参考文章:https://www.cnblogs.com/zhaoyanjun/p/5175502.html

  github地址:https://github.com/ReactiveX/RxJava  和  https://github.com/ReactiveX/RxAndroid

18.首页功能完成。

  只要研究好一个页面,基本上其他页面都不在话下了。

  因为这个页面,进行了网络请求,视图绑定,BaseFragment定义,接口API请求等,基本上能做的事情,这个页面都会做。

  除此之外,还有一些通用的工具包,首页Bean类型的定义,首页的布局文件,抽屉的布局,只不过没有处理点击事件。

  预览页面如下:

  

  然后仅仅完成首页之后,我进行打包,方便以后使用。

  百度云链接:https://pan.baidu.com/s/1VCiuVy21RLMOHflN9MP19A

  密码:hmci

  之后的过程应该就是举一反三了!

  这里我总结一下过程:(想到哪写到哪)

      1.首先定义了一个抽象类BaseFragment,让这个每日推荐的Fragment来继承它。不单单继承,还要求传入一个泛型类,这个泛型类继承ViewDataBinding。

        这里就是为了方便处理数据的,因为用到MVVM模式,所有声明了layout的视图都生成一个视图绑定类,进而可以获取到数据。个人觉得就是为了简化

        从视图中findViewById的过程,其实在用的时候,还是有一次赋值的过程,不过就不用以前那么麻烦地看视图id了。 

        言归正传,这个BaseFragment同样继承了Fragment,注意是v4的Fragment,这里是一坑。

        然后这个BaseFragment主要干什么?

        布局很简单,最外层LinearLayout,里面一个RelativeLayout,再里面就是两个LinearLayout,分别是正在加载和加载失败的图片及文字的显示。

        所以啊,布局中的RelativeLayout其实就是显示内容的,要么这个内容为正在加载,要么为加载失败,要么就是内容了,就这三种情况。

        值得一提的是,使用MVVM模式是如何将内容添加到这个RelativeLayout中呢?

        这里其实是用了DataBindingUtil.inflate方法,动态生成一个泛型类(继承于ViewDataBinding),然后用RelativeLayout.addView方法添加即可。

        回想一下Fragment的生命周期~

        首先onAttach->onCreateView->onCreate->onActivityCreate->onStart->onResume,到这里视图才能真正展示。。。

        所以在onActivityCreate中可以做什么呢?

        答案当然就是:开启动画啦。然后就是设置失败刷新的点击事件。反正这里就是需要干嘛就干嘛。

        然后还有一些方法,比如显示加载中状态,加载完成状态,加载失败状态,主要处理视图的隐藏,这里还是简单。主要方便继承者调用嘛。

        重要点1:然后就是实现Fragment数据的缓加载,其实就是判断fragment是否可见,可见才进行请求。

        重要点2:然后需要添加一条消息,就是你数据在一个子线程里请求请求请求...完成之后,要通过一条消息发送给主线程,主线程来处理数据。

               注意在onDestroy中,将这条消息取消掉,否则内存泄漏就惨咯,然后自己也写一个移除方法。 

      2.好了,现在有BaseFragment了。那么现在还需要对当前页面单独设置一个接口,用来实现仅仅这个页面才会做的一些方法。

        对于主页来说,我需要显示轮播图,显示主页列表,显示主页错误页面,显示旋转动画,取主页缓存。

      3.然后就是EverydayFragment的具体实现了,原来在这里面才真正开启动画的,所以这样的话会更加灵活处理各种页面动画。

        原来这里不是用的BaseFragment中的动画,他是自己单独写的一个动画。所以在它自己的布局中有一个独特的动画图。

        这里的需要定义一个类似于之前MVP模式中的P(presenter),这里因为用到MVVM模式,所以效果是一样的,不过这里名字为viewModel了。

      4.来看一下这个处理器吧。(我习惯称处理网络请求的东西叫做处理器,不过这里进行了两次封装,还有一个我就叫具体网络请求器吧)

        这里还包装了一层,将真正的网络请求封装了。

        首先看一下第一层处理器。

        在构造器里面建立了一个具体网络请求器的实例。这个可以叫做创建型模式吧。

        简单理一下网络数据加载过程:

          在处理器中调用了网络请求器的同名的方法,用了一个接口作为回调3种情况,1个是成功,1个是加载失败,1个是添加消息给basefragment。

          如果加载成功,则显示数据,然后将缓存清理,重新添加最新的缓存。如果没有数据列表,则从缓存中拿,缓存也没有,则重新请求。

          如果加载失败,就尝试从缓存中读取,如果缓存有数据,就显示列表数据。如果缓存也没数据,则显示BaseFragment中定义的错误界面。

        然后看一些这个具体网络请求器干了些什么?

          首先是具体请求轮播图。调用的过程真的太讲究了,得好好学学别人的封装过程。

          首先是定义了一个同名的请求方法后,里面传入了一个接口,主要是处理具体的回调。

        网络封装过程:

          首先HttpClient是一个网络请求类,这是一个接口。因为每个接口会有一个BaseUrl。

          这个HttpClient里面有一个Builder类,里面处理各种请求,返回的都是HttpClient对象。

          为什么会返回HttpClient对象呢?因为这里还用了一个BuildFactory类,来封装Retrofit请求,设置一些请求参数等。

          最后还是要回到HttpClient,然后这里面还有请求的具体参数写的API请求,返回Observable<T>类型数据。

        

        5.获取到网络数据后该怎么显示呢?

          答案就是适配器了。

          在哪里设置适配器?

          这个就得看着自己了,在继承BaseFragment的类中设置。在这个继承BaseFragment中有很多实例,如绑定Header布局对象,绑定Footer布局对象,

            当前Fragment的适配器,当前Fragment的ViewModel。

          这个Header布局对象就是当前Fragment页面最上方的布局,一个banner,一个4个图标入口。使用RecycleView.addHeaderView方法即可。

          如果RecyclerView滑动不流畅,需设置recylerView.setNestedScrollingEnabled(false);

          注意在onPause中停止全部图片请求,在onResume继续图片请求。

          这个适配器就是处理数据显示的一个关键类了。

          首先他继承了BaseRecyclerViewAdapter,无赖,只能硬着头皮先看BaseRecyclerViewAdapter了。

          这个BaseRecyclerViewAdapter也是继承了RecyclerView.Adapter<BaseRecyclerViewHolder>,无赖,还得先了解BaseRecyclerViewHolder啦

          BaseRecyclerViewHolder主要就是一个视图持有者,竟然定义了两个泛型,T是我们的数据类型,D是一个视图绑定类。

          因为继承了RecyclerView.ViewHolder,那么它的作用也就是容纳视图的作用了。所以这个BaseRecyclerVIewHolder的作用就是执行

            ViewDataBinding的一个executePendingBindings方法而已。

          BaseRecyclerViewAdapter所以就该实现父类中定义的抽象方法onBindViewHolder了。其他就是一些数据的增加删除获取了。

          EverydayAdapter正是继承了BaseRecyclerViewAdapter了,然后具体实现了两个必须实现的方法,getItemViewType,onCreateViewHolder了

19.对于适配器中的getItemViewType的理解。

  现在才真正理解适配器中的函数。

  其实里面的position,并不是一开始就加载完。而是加载到手机屏幕高度,就是说position只会填充完当前手机屏幕。

  然后滑动手机屏幕后,这个position才会做相应的改变。

20.学会了自定义处理WebView的活动(通用)。

  现在的APP基本都会用到webView,特别是类似于微信那种自带进度条的WebView很常见。

  所以现在新建了一个专门处理webView的活动,可能只是这个项目通用吧,不同项目根据自己需求酌情修改即可。

  这个网页可以处理很多东西,拨打电话,发送短信,上传图片,播放视频,循环显示网页标题,进度条,可以说比较通用吧。

  参考文章:https://github.com/youlookwhat/WebViewStudy

  

          

21.以后再补充。

从Github开源项目《云阅》所学到的知识的更多相关文章

  1. iOS:开发常用GitHub开源项目(持续更新)

    IOS开发常用GitHub开源项目(持续更新) 数据类 开源库 作者 简介 AFNetworking Mattt 网络请求库 ASIHTTPRequest pokeb 网络请求库 Alamofire ...

  2. 【Github开源项目体验】- ZFile 基于 Java 的在线网盘

    [Github开源项目体验]- ZFile 基于 Java 的在线网盘 在线云盘.网盘.OneDrive.云存储.私有云.对象存储.h5ai.上传.下载 date: 2022-08-02 addres ...

  3. 2015-2016最火的Android开源项目--github开源项目集锦(不看你就out了)

    标签: Android开发开源项目最火Android项目github 2015-2016最火的Android开源项目 本文整理与集结了近期github上使用最广泛最火热与最流行的开源项目,想要充电与提 ...

  4. 如何参与一个 GitHub 开源项目?

    最近一年开源项目特别的热,很多技术大会或论坛都以开源项目作为主题进行探讨,可见这是一种趋势.而Github作为开源项目的著名托管地,可谓无 人不知,越来越多的个人和公司纷纷加入到Github的大家族里 ...

  5. Android笔记——导入Github开源项目CircleRefreshLayout

    百度n久都找不到android studio导入第三方类库的正确方法,纠结睡不着 ,最后终于蒙到了方法,原来想太多了  ---------------------------------------- ...

  6. 如何参与一个GitHub开源项目

    Github作为开源项目的著名托管地,可谓无人不知,越来越多的个人和公司纷纷加入到Github的大家族里来,为开源尽一份绵薄之力.对于个人来讲,你把自己的项目托管到Github上并不表示你参与了Git ...

  7. 开源项目福利-github开源项目免费使用Azure PipeLine

    微软收购Github后,很多人猜想微软可能会砍掉VSTS,然而事实VSTS并没有砍掉,关于Azure Devops的详细信息可以查看 这篇博客,如果想查看原文也可以从链接里提供的原始地址里查看. 今天 ...

  8. 基于RBAC模型的权限系统设计(Github开源项目)

    RBAC(基于角色的访问控制):英文名称Rose base Access Controller.本博客介绍这种模型的权限系统设计.取消了用户和权限的直接关联,改为通过用户关联角色.角色关联权限的方法来 ...

  9. Android Hawk数据库 github开源项目

    Android Hawk数据库 github开源项目 Hawk 是一个很便捷的数据库  . 操作数据库仅仅需一行代码 , 能存不论什么数据类型 . github 地址: https://github. ...

  10. [Android开源项目] GitHub开源项目总结 (转)

    [Android开源项目] GitHub开源项目总结 GitHub开源项目android-styled-dialogs http://neast.cn/forum.php?mod=viewthread ...

随机推荐

  1. July 20th 2017 Week 29th Thursday

    The darkness is no darkness with you. 有了你,黑暗将不再是黑暗. The darkness will not be driven out if we failed ...

  2. easyui学习笔记12—tab标签页的添加和删除

    这一篇我们来看看标签页的添加和删除动作.我在想看这些例子还不如看文档,文档的内容更加全面,但是文档全部是理论没有实际的操作,看起来很枯燥,文档只能是遇到问题的时候查.easyui的文档写的还是很详细的 ...

  3. ZT 段祺瑞终生忏悔枪杀学生?

    段祺瑞终生忏悔枪杀学生?http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece76310528c315c4380146080955468d4e4 ...

  4. Yii日志使用

    Yii 提供了一个灵活可扩展的日志功能.记录的日志 可以通过日志级别和信息分类进行归类.通过使用 级别和分类过滤器,所选的信息还可以进一步路由到 不同的目的地,例如一个文件,Email,浏览器窗口等. ...

  5. xml-apis-ext.jar

    xml-apis-ext.jar,hightcharts导出图片是解决乱码需要用到的一个包

  6. bzoj5152 [Wc2018]通道

    题目链接 正解:不会做. 写一个爬山算法就过官方数据了(逃 具体来说就是每次随机一个根,然后迭代找最长路的那个点. 多随机几次取$max$就行了.正解以后再补.. #include <bits/ ...

  7. vue通过watch对input做字数限定

    <div id="app"> <input type="text" v-model="items.text" ref=&q ...

  8. 常用的css选择器

    1.最基本的 * * 选择所有元素. #id #firstname 选择 id="firstname" 的元素. .class .intro 选择 class="intr ...

  9. mint-ui 填坑之路

    swipe组件 因为项目加载eslint的缘故也就没有像之前的项目一样引用swiper框架.这个轮播图的组件文档实在是不敢恭维(尽管其他的文档也好不到哪里去),官方给出的参数真是少的可怜,一些方法也并 ...

  10. 说说DBA职责和目标

    数据库管理员(Database Administrator,简称DBA),是从事管理和维护数据库管理系统(DBMS)的相关工作人员的统称,他属于运维工程师的一个分支,主要负责业务数据库从设计.测试到部 ...