Giter VIP home page Giter VIP logo

blog's Introduction

Hi there 👋

Folio Reader 那样记账

blog's People

Contributors

bakumon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

blog's Issues

关于 Android Studio 配置方法数超过 64k 限制问题

版权声明:本文为 Bakumon 原创文章,转载需在明确位置注明出处!!!#13


项目中因为使用到了 Rxjava 等库,导致方法数超过了 64k 限制。于是准备使用 multidex 方案来解决,从此掉入了坑中。

ps:一般的项目如果出现了 64k 限制问题,首先必须考虑的是替换那些只为了方便使用一个小功能而引入的比较大的库,而不是使用下面要介绍的规避 64k 限制的方法。

首先得吐槽一下,开启 multidex 后,打包的速度简直不能再慢,打完一个包,我都可以喝完一杯咖啡了。。热爱生命的我们是最好不会使用它。

1.修改模块级 build.gradle 文件

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"

    defaultConfig {
        ...
        minSdkVersion 14
        targetSdkVersion 21
        ...

        // Enabling multidex support.
        multiDexEnabled true
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.0'
}

2.引用 MultiDexApplication 类

有两种方法来引用 MultiDexApplication 类,选一种使用即可。

  1. 继承 MultiDexApplication
public class MyApplication extends MultiDexApplication {
    ...
}
  1. 重写 Application 的 attachBaseContext 方法
public class MyApplication extends Application {
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}

记得在清单文件中注册 Application

<application
    ...
    android:name=".MyApplication">
    ...
</application>

友情提示:
千万不要忘了引用 MultiDexApplication 类这一步骤,否则,app 在 Android 5.0 以下版本中使用 umeng 统计会闪退,错误信息如下:

java.lang.NoClassDefFoundError: com.umeng.analytics.d

这是 umeng 论坛上给出的解决方法。 http://bbs.umeng.com/thread-16063-1-1.html

Android Studio 插件整理

版权声明:本文为 Bakumon 原创文章,转载需在明确位置注明出处!!!#9


Android Studio 是基于 Jetbrains IDE ,得益于 Jetbrains IDE 的插件众多以及 Google 对 AS 的推广,使得 AS 也有了越来越多优秀的插件 👍

AS 安装插件有两种方法:

在线:
Preferences(Settings) > Plugins > Browse repositories... > 搜索插件关键字 > Install Plugin

离线:
下载插件的 jarzip -> Preferences(Settings) > Plugins > Install plugin from disk...

安装成功后需重启IDE.

1.TranslationPlugin

提示: 申请自己的有道翻译 API key,否则使用默认的 API key ,大家一起用,很容易达到上限的。

稳定强大的翻译插件,拥有强大实用性强的 action。比如 翻译并替换 Alt + R

action1

2.eventbus-intellij-plugin

eventbus 的事件导航,这个太方便了。

eventbus :eventbus-intellij-plugin

eventbus3 :eventbus3-intellij-plugin

cap 1

3.Android-ButterKnife-Plugin-Plus

自动生成 ButterKnife 注解代码

1

4.CodeGlance

右侧预览代码,可快速定位,效果同 Sublime Text

codeglance

5.Emoji Support

提交 commit 时,支持输入 emoji 表情时提示功能

emoji

6.PGYASPlugin

蒲公英上传内测 apk 插件,简直不能再方便,直接在 AS 中就可以上传 apk。

pgyerplugin

7.GsonFormat

根据 json 字符串自动生成实体类属性

fd

8.Android Parcelable boilerplate code generation

快速为实体类实现Parcelable接口

parcelable

9.Android Methods Count

显示出依赖库的方法数

screenshot_15509

10.Android-DPI-Calculator

DPI 计算器,根据任意一个 dpi 计算其他 dpi 值

dpi

11.SingletonTest

提供生成六种 java 单例代码

LazyUnSafe,LazySafe,Hungry,DoubleCheck,StaticInner,Enum;

singleton

12.Lifecycle-Sorter

为 Activity 和 Fragment 的生命周期回调函数排序

lifecycle

神奇的 Drawable 文件夹——介绍篇

版权声明:本文为 Bakumon 原创文章,转载需在明确位置注明出处!!!#8


Android 原生支持 MVC 模式,我们不必用 java 代码来 new 出界面中所有控件类,再组合起来,最后加载到界面上,而是利用 xml 文件的层级关系和节点的可自定义,组合出我们想要的布局方式,并且强大的 IDE 可以实时预览界面。所有的 xml 文件中的节点都对应一个存在的类,可能是控件或者下面说到的 Drawable,Drawable 是一种可以用来给控件设置背景等的图形对象,在 xml 文件中定义 Drawable,更方便设置控件的背景或者文本颜色等。

Drawable 的各种实现类可以在项目的 src/main/res/drawable 下建立 xml 文件,增加不同的节点来实现。下表是一些常用的 Drawable,和对应节点以及说明。

序号 节点 Drawable 具体子类 说明
1 bitmap BitmapDrawable 对bitmap的封装
2 color ColorDrawable 表示纯颜色的 Drawable
3 shape ShapeDrawable 绘制基础的形状图形,可用于定义圆角、渐变色、圆环等效果
4 selector StateListDrawable 表示一组有状态的 Drawable 集合,即选择器
5 level-list LevelListDrawable 表示一组有等级的图像的集合
6 layer-list LayerDrawable 表示图层
7 nine-patch NinePatchDrawable 对.9.png的封装
8 clip ClipDrawable 对drawable裁剪
9 inset InsetDrawable 有内边距的 Drawable 对象
10 ripple RippleDrawable 波纹点击效果,API21以上

下面看怎样在 xml 文件中使用这些 Drawable,当然和布局文件中的 view 一样,我们也可以使用 java 代码来创建这些对象,但是我们一般不这样做,就像我们不会用 java 代码创建一个复杂的布局一样。
注:必要时也需要用 java 代码的方式来实现。

一、BitmapDrawable

在 drawable 文件夹下创建一个名为bitmap.xml的文件(名称可以随意),修改 <selector/> 根节点为 <bitmap/>,并且增加 src 属性,像下面这样:

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_launcher">
</bitmap>

这样我们就可以在文件文件中设置 view 的背景 android:background="@drawable/bitmap",bitmap 的使用就这么简单,一般使用 bitmap 也是配合别的 Drawable,用于包装图片资源,比如在 StateListDrawable(selector节点)下,对应每一个drawable 设置不同的 BitmapDrawable。

bitmap 节点下不能再包含子节点。所有的设置都通过属性来完成。

下表列出所有的属性供参考。

属性 参数类型 说明
android:src Drawable resource 显示的图片,不能为color等,只能为图片资源
android:alpha float 透明度0-1,值越小,越透明
android:antialias boolean 是否开启抗锯齿
android:autoMirrored boolean 设置图片是否需要镜像反转,当布局方向是RTL,即从右到左布局时才有用,API19以上
android:dither boolean 是否抖动
android:filter boolean 设置是否允许对图片进行滤波
android:gravity center... 图片对其方式,同布局文件中view的gravity属性
android:mipMap boolean 设置是否可以使用mipmap API18以上
android:tileMode disabled、mirror、clamp、repeat X、Y轴平铺方式, disabled(默认):不使用平铺;mirror:镜面;clamp:复制图片边缘的颜色来填充容器剩下的空白部分;repeat:图片重复铺满
android:tileModeX 同上 X轴平铺方式,参数意义同上
android:tileModeY 同上 Y轴平铺方式,参数意义同上
android:tint color 给图片着色
android:tintMode add、multiply、screen、src_atop、src_in、src_over 着色模式

二、ColorDrawable

ColorDrawable 对应xml文件中的 <color/> 节点,同样在 drawable 文件夹下新建一个名为color.xml的文件(名称可以随意),内容如下:

<?xml version="1.0" encoding="utf-8"?>
<color xmlns:android="http://schemas.android.com/apk/res/android"
       android:color="@color/colorAccent">
</color>

color 节点只有唯一一个也是必须的属性,android:color 使用color资源文件中的color赋值即可。同样没有子节点,最为简单的一个 Drawable ,把 color 值转化为了 Drawable 对象,以便在其他需要 Drawable 的地方使用。

三、ShapeDrawable

使用 <shape/> 节点用来定义形状,可以定义矩形、椭圆、线、圆环四种类型的形状。shape 节点包含一些属性和子节点:

属性:

属性 参数类型 说明
android:shape rectangle、oval、line、ring 定义形状的类型,rectangle(矩形)、oval(椭圆)、line(线)、ring(圆环)默认为矩形
android:innerRadius int 圆环内圆的半径
android:innerRadiusRatio int 内半径占整个Drawable宽度的比例,默认值为9
android:thickness int 圆环的厚度
android:thicknessRatio int 厚度占整个Drawable宽度比例,默认值为3
android:useLevel boolean 设置等级,配合LevelListDrawable使用时设置
android:visible boolean 设置是否可见
android:dither boolean 是否抖动
android:tint color 给图片着色
android:tintMode add、multiply、screen、src_atop、src_in、src_over 着色模式

子节点:

3.1 solid 填充色

表示形状的填充色,只有一个属性:android:color

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/colorAccent"/>
</shape>

solid1

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="oval">
    <solid android:color="@color/colorAccent"/>
</shape>

solid2

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:innerRadius="50dp"
       android:shape="ring"
       android:thickness="10dp"
       android:useLevel="false">
    <solid android:color="@color/colorAccent"/>
</shape>

solid3

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="line">
    <stroke
        android:width="4dp"
        android:color="@color/colorAccent"
        android:dashGap="8dp"
        android:dashWidth="4dp"/>
</shape>

solid4

3.2 corners 圆角

表示圆角的半径,对应有四个角的属性,和一个总体的属性

属性 参数类型 说明
android:radius int 统一设置圆角半径
android:bottomLeftRadius int 设置左下角圆角半径
android:bottomRightRadius int 设置右下角圆角半径
android:topLeftRadius int 设置左上角圆角半径
android:topRightRadius int 设置右上角圆角半径
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <corners
        android:bottomLeftRadius="3dp"
        android:radius="5dp"/>
    <solid android:color="@color/colorAccent"/>
    <size
        android:width="30dp"
        android:height="30dp"/>
</shape>

radius

3.3 gradient 渐变色

表示渐变色,可以设置形状填充的颜色为渐变色

属性 参数类型 说明
android:angle int 设置旋转的角度,45的倍数
android:startColor color 颜色变化的起始值
android:endColor color 颜色变化的结束值
android:centerColor color 中间的颜色
android:centerX int 渐变中心点的横坐标
android:centerY int 渐变的中心点的纵坐标
android:gradientRadius int 渐变的梯度,当android:type=”radial”有效
android:type linear 、 radial 、 sweep 渐变类别,linear(线性)为默认值,radial(径内渐变),sweep(扫描渐变)
android:useLevel boolean 设置等级,配合LevelListDrawable使用时设置
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:type="sweep"
        android:endColor="@color/colorAccent"
        android:startColor="@color/colorPrimary"/>
    <size
        android:width="30dp"
        android:height="30dp"/>
</shape>

gradient

3.4 stroke 边框

表示边框。

属性 参数类型 说明
android:color color 边框颜色
android:width int 边框宽度
android:dashGap int 边框虚线间隙大小
android:dashWidth int 边框虚线每个小节的宽度
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke
        android:width="2dp"
        android:color="@color/colorAccent"
        android:dashGap="2dp" // 和dashWidth一起设置,若不设置则为实线
        android:dashWidth="3dp"/>
    <size
        android:width="30dp"
        android:height="30dp"/>
</shape>

stroke

3.5 size 大小

设置背景大小,width 和 height 两个属性。一般来说这个值不是 shape 的最终显示大小,因为 shape 作为背景时会根据 View 的大小而填充其背景,所以 Shape 的大小很多时候是 View 的大小决定的。

3.6 padding 内边距

表示内容或子标签边距,4个属性top、bottom、left、right,需要注意的是这个标签的作用是为内容设置与当前应用此 shape 的 View 的边距,而不是设置当前 View 与父元素的边距。

四、StateListDrawable

StateListDrawable 对应 drawable 文件夹下的xml文件的 <selector/> 节点,表示drawable集合。selector 可以包含不止一个 item 节点,每个 item 节点对应两类属性,一类只有一个 android:drawable, 另一类是类似于 android:state_pressed,表示当前所在 view 的状态,有按下、选择、获得焦点等十几种状态,需要注意不是每一个 view 都有这么多状态。
最常见的场景是给 Button 设置点击和正常状态下的 drawable。

selector 节点 属性:

属性 参数类型 说明
android:autoMirrored boolean 设置图片是否需要镜像反转
android:constantSize boolean 设置自身大小是否随着其状态改变而改变
android:enterFadeDuration int 状态改变时,新状态展示时的淡入时间,以毫秒为单位
android:exitFadeDuration int 状态改变时,新状态消失时的淡入时间,以毫秒为单位
android:variablePadding boolean padding是否随状态的改变而改变,默认false

子节点 item 属性:

属性 参数类型 说明
android:drawable drawable 对应drawable,可以为color、bitmap、shape等单一drawable
android:android:state_xxx boolean 设置不同的状态
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/button_press"
          android:state_pressed="true"/>
    <item android:drawable="@color/button_norm"
          android:state_pressed="false"/>
</selector>

子节点 item 还可以包含许多子节点,如 bitmap、shape、color、动画相关的等,下面给出两个例子说明用法。

在布局文件中给view设置 android:background="@drawable/button_seleter" 即可,实现在点击view时显示不同的背景图,有点击的效果反馈。

这里需要注意一点:
如果上边所说的view是 Button 的话,直接可以看到效果,但是,实际开发中,我们可能要给 LinearLayout、TextView 设置点击效果,使用上面的方法是没有效果的。

解决方法:给这个 view 添加点击事件的监听。

上边代码中的 android:drawable 不只可以设置为 color 类型的 drawable,还可以设置为 bitmapDarwable、ShapeDrawable 等,下面看一个圆角点击效果的例子。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="false">
        <shape>
            <corners android:radius="10dp"/>
            <solid android:color="@color/button_norm"/>
        </shape>
    </item>
    <item android:state_pressed="true">
        <shape>
            <corners android:radius="10dp"/>
            <solid android:color="@color/button_press"/>
        </shape>
    </item>
</selector>

设置在 view 上的效果为有圆角效果,并且按下的时候,背景后改变。
以上代码在 selector 节点下有两个 item 节点,item 节点设置了是否点击的状态,并且包含了一个 shape 节点,作为对应状态下的 drawable 对象。

五、LevelListDrawable

LevelListDrawable 对应xml文件中的 <level-list/> 节点,表示一组由等级大小标志的 drawable,不同的等级可以为之设置不同的背景 drawable。

此节点没有参数,只能包含不止一个的 item 子节点。

item 节点的属性:

属性 参数类型 说明
android:drawable drawable 对应drawable,可以为color、bitmap、shape等单一drawable
android:maxLevel int 设置等级范围的最大值
android:minLevel int 设置等级范围的最小值
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@color/colorAccent"
        android:maxLevel="10"
        android:minLevel="1"/>
    <item
        android:drawable="@color/colorPrimary"
        android:maxLevel="20"
        android:minLevel="11"/>
</level-list>

简单起见,使用 ColorDrawable 来设置对应的 android:drawable,有两种不同的背景,对应都有不同的等级范围。
设置给view 作为背景,像这样:android:background="@drawable/level"

在 java 代码中,获取到此 view 的 background,再设置其 level 属性的值,就会变为对应等级的背景。

boolean flag;

public void onClick(View v) {
    if (flag) {
        view.getBackground().setLevel(3);
    } else {
        view.getBackground().setLevel(13);
    }
    this.flag = !this.flag;
}

六、LayerDrawable

LayerDrawable 也表示 drawable 集合,对应xml文件中的<layer-list/>节点,根据名称我们可以知道其中的每一个 drawable 都代表一个图层,新加入的 drawable 位于背景图片的最高图层。
item 的 android:drawable 属性也是可以设置为复杂的 drawable 的,方便起见,这里使用 colorDrawable。

属性 参数类型 说明
android:opacity transparent、translucent、opaque 设置透明度:transparent透明、translucent半透明、opaque不透明
android:paddingXxx int 设置等级范围的最大值

子节点 item 属性,都是定位的属性,像height,width,gravity,bottom,top,left,right等。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:bottom="10dp"
        android:drawable="@color/colorAccent"
        android:left="10dp"
        android:right="10dp"
        android:top="10dp"
        />
    <item
        android:bottom="50dp"
        android:drawable="@color/colorPrimary"
        android:left="50dp"
        android:right="50dp"
        android:top="50dp"
        />
</layer-list>

效果如下:

layer

七、NinePatchDrawable

NinePatchDrawable 是点九图的封装,xml文件中对应 <nine-patch/> 标签,属性和 BitmapDrawable 中属性的含义相同。

<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"   
    android:src="@drawable/btn_bk"
    android:dither="true"/> 

八、ClipDrawable

ClipDrawable 代表可以裁剪的 drawable,对应xml文件中的<clip/>标签,通过当前设置的比例来裁剪Drawable,ClipDrawable 的 setLevel() 方法可以控制显示比例,ClipDrawable的level值范围在[0,10000],level 的值越大裁剪的内容越少,当 level 为 10000 时则完全显示,而 0 表示完全裁剪,不可见。

<clip/>标签的属性:

属性 参数类型 说明
android:drawable drawable 对应drawable,可以为color、bitmap、shape等单一drawable
android:clipOrientation horizontal、vertical 裁剪的方向,horizontal水平、vertical垂直
android:gravity right、top等 设置drawable所在位置,配合android:clipOrientation属性一起用

android:gravity 可以设置下表所示的值:

属性 描述说明
top 将这个对象放在容器的顶部,不改变其大小。当clipOrientation 是”vertical”,裁剪从底部开始
bottom 将这个对象放在容器的底部,不改变其大小。当clipOrientation 是”vertical”,裁剪从顶部开始
left 将这个对象放在容器的左部,不改变其大小。当clipOrientation 是 “horizontal”,裁剪从drawable的右边(right)开始,默认值
right 将这个对象放在容器的右部,不改变其大小。当clipOrientation 是 “horizontal”,裁剪从drawable的左边(left)开始
center 将这个对象放在水平垂直坐标的中间,不改变其大小。当clipOrientation 是 “horizontal”裁剪发生在左右。当clipOrientation是”vertical”,裁剪发生在上下。
center_vertical 将对象放在垂直中间,不改变其大小,如果clipOrientation 是 “vertical”,那么从上下同时开始裁剪
center_horizontal 将对象放在水平中间,不改变其大小,clipOrientation 是 “horizontal”,那么从左右两边开始裁剪
fill 填充整个容器,不会发生裁剪。(除非drawable的level是 0,才会不可见,表示全部裁剪完)。
fill_vertical 垂直方向上不发生裁剪。(除非drawable的level是 0,才会不可见,表示全部裁剪完)
fill_horizontal 水平方向上不发生裁剪。(除非drawable的level是 0,才会不可见,表示全部裁剪完)
clip_vertical 附加选项,表示竖直方向的裁剪,很少使用
clip_horizontal 附加选项,表示水平方向的裁剪,很少使用
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
      android:clipOrientation="horizontal"
      android:drawable="@drawable/ic_launcher"
      android:gravity="right">
</clip>

上边代码定义了一个 ClipDrawable 对象,设置进行水平方向裁剪,并且从左边开始裁剪。drawable 为 app 启动图标。

在布局文件的view中使用像 android:background="@drawable/clip" 代码来使用上边定义的 ClipDrawable。

在 java 代码中,通过设置 ClipDrawble 的 level 属性的值,来进行图片背景的裁剪。

linearLayout = (LinearLayout) findViewById(R.id.lll);
linearLayout.getBackground().setLevel(5000); // 裁剪一半,0~10000

效果如下图:

clip

九、InsetDrawable

InsetDrawable 用距离边框的距离表示 drawable 大小,比如我们需要让view的背景不是完全填充这个 view,并且需要一定的距离,就可以使用 InsetDrawable 来完成。InsetDrawable 对应xml文件中的 <inset/> 标签。

属性:

属性 参数类型 说明
android:drawable drawable 对应drawable,可以为color、bitmap、shape等单一drawable
android:inset dimen 统一设置距离边框的距离
android:insetTop dimen 设置距容器上边的距离
android:insetBottom dimen 设置距容器下边的距离
android:insetLeft dimen 设置距容器左边的距离
android:insetRight dimen 设置距容器右边的距离
android:visible boolean 设置是否可见
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
       android:drawable="@color/colorAccent"
       android:inset="10dp">
</inset>

十、RippleDrawable

RippleDrawable 可以在 Android5.0 即 API21 以上实现波纹点击效果,对应 xml 文件中的 <ripple/> 标签。由于此标签必须在 API21 以上才可以使用,我们也不能设置 minSdkVersion 为21,毕竟要适配更多的API版本,我们可以在建立一个 drawable-v21 的文件夹,在里面新建一个xml文件即可。

在 Android studio 中,就更方便了,选中 Drawable 文件夹--->右键--->选择new--->单击 Drawable resource file 选项,就来到了如下对话框:

ripple

填写文件名,选择最后一个 Version,单击中间的表示向右的按钮,填写 21,点击 ok,就会自动生成对应文件和新建文件。

<ripple/> 标签的属性:

属性 参数类型 说明
android:color color 波纹的颜色,会覆盖在背景上
android:radius dimen 圆角,不太懂,设置大小效果都一样
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="@color/gray">
    <!--有界-->
    <item
        android:id="@android:id/mask"
        android:drawable="@color/gray"/>
</ripple>

需要注意的是 android:id="@android:id/mask",没有设置时,是无边界的波纹效果,添加后为有边界。

ripple2

参考博文:

领略千变万化的Android Drawable (一)

领略千变万化的Android Drawable (二)

Android样式的开发:drawable汇总篇

参考视频教程:

[慕课网]Android的各种Drawable讲解

Ubuntu 安装 Android Studio 的步骤

版权声明:本文为 Bakumon 原创文章,转载需在明确位置注明出处!!!#4


在 ubuntu 上进行 Android 开发也有一段时间了,以前用的是 ubuntu 14.04 ,在16.04 发布后迅速升级了系统版本,接触 ubuntu ,从一开始的各种主题,桌面的折腾,到现在的简单、简洁的配置,专注于开发,反而离不开 ubuntu 了,Linux 是一个非常伟大的系统。下面记录一下在 Ubuntu 上安装 Android Studio 的步骤,以便以后查用。

安装 JAVA

首先必须是安装 JAVA 环境,最直接简单的方法如下,第三步会下载 java SDK,比较费时。

sudo add-apt-repository ppa:webupd8team/java

sudo apt-get update

sudo apt-get install oracle-java8-installer

sudo apt-get install oracle-java8-set-default

安装 Android Studio

接着下载 Android Studio 软件包,下载 Android Studio ,以下内容摘自官方安装说明

🚶🚶🚶喜大普奔,google 出品了开发者文档中文网,下载 studio、看官方文档再也不用翻墙了

https://developer.android.google.cn

安装 Android Studio 只需轻松点击几下。(您需要已下载 Android Studio。)

如需在 Linux 系统中安装 Android Studio,请执行以下操作:

  1. 将您下载的 .zip 文件解压缩到您应用的相应位置,例如 /usr/local/(适用于用户个人资料)或 /opt/(适用于共享用户)。
  2. 要启动 Android Studio,请打开一个终端,导航至 android-studio/bin/ 目录,并执行 studio.sh
    提示:将 android-studio/bin/ 添加至您的 PATH 环境变量,这样您就可以从任何目录启动 Android Studio。
  3. 选择是否想要导入之前的 Android Studio 设置,然后点击 OK
  4. 之后 Android Studio 设置向导将指导您完成余下的设置,包括下载开发所需的 Android SDK 组件。

:如果您运行的是 64 位版本 Ubuntu,则您需要使用以下命令安装一些 32 位库:

sudo apt-get install lib32z1 lib32ncurses5 lib32bz2-1.0 lib32stdc++6

如果您运行的是 64 位版本的 Fedora,则所用命令为:

sudo yum install zlib.i686 ncurses-libs.i686 bzip2-libs.i686

对官方安装说明的补充

  1. 如遇到 lib32* 没有找到的问题,可执行
sudo apt-get install lib32stdc++6
  1. 安装文件 .zip 解压到任何目录都可以
  2. 打开 Android Studio 后可以单击右下角 configure 选项,选择 Create Desktop Entry 生成 Dash 图标,方便启动。
    ps: 通过 studio.sh 启动关闭终端 Studio 也会跟着退出。
  3. 配置环境变量方便使用adb:
sudo gedit /etc/profile

在文件末尾加上

#set android adb sdk tools
export PATH=$PATH:sdk安装目录全路径/tools
export PATH=$PATH:sdk安装目录全路径/platform-tools

以上代码把 toolsplatform-tools 加入了全局环境变量,需要重启电脑生效。

Ubuntu 利用 crontab 和 notify-send 定时发送桌面通知,提示该休息啦

版权声明:本文为 Bakumon 原创文章,转载需在明确位置注明出处!!!#11


notify-send

notify-send 是 Linux 下发送通知到桌面的命令行程序。Ubuntu16.04 会在桌面右上角出现一个通知提醒框。

基本用法:

  1. 发送一条通知内容
    notify-send "这是通知的内容"

  2. 发送一条有标题的通知
    notify-send "标题" "这是通知的内容"

  3. 发送一条有图片的通知
    notify-send /home/tip.png "标题" "这是通知的内容"

crontab

crontab 是 Linux 下的定时任务,服务端一般用于定时重启某些服务、定时清理日志信息等。

  1. 执行命令
sudo crontab -l

查看定时任务列表,如果有的话,将会列出来

  1. 执行命令
sudo crontab -e

进入编辑 crontab 的模式下。

语法是这样的:

minute hour day month week command
参数 说明
minute 分钟,0到59
hour 小时,0到23
day 日期,1到31
month 月份,1到12
week 星期,0到7,这里的0或7代表星期日
command 要执行的命令,命令行命令,或者外部脚本文件

例子:

  1. 每分钟都执行一次 command
    * * * * * command

  2. 每小时的 2 和 3 分钟时执行一次 command
    2,3 * * * * command

  3. 10 点到 18 点之间每个小时的 2 和 3 分钟都执行一次 command
    2,3 10-18 * * * command

  4. 晚上 11 点到早上 7 点之间,每隔 2 小时重启smb
    * 23-7/2 * * * /etc/init.d/smb restart

结合出功能--每两个小时提示用户该休息啦

执行命令 sudo crontab -e 进入定时任务编辑模式,在最后一行加入以下代码:

0 */2 * * * export DISPLAY=:0.0; notify-send /home/tip.png "休息" "滚去休息吧!!!"

保存退出即可,偶数小时的 0 分钟就会有 “去休息” 的提示。

Note:
要在定时任务里调用图形界面程序,需要加上 export DISPLAY=:0.0; 环境变量,告诉定时任务图形界面程序显示的屏幕。

属性动画 ValueAnimator 在自定义 View 中的使用

版权声明:本文为 Bakumon 原创文章,转载需在明确位置注明出处!!!#6


功能强大的属性动画(property animation)

最近在学习有关自定义 View 的内容,在 Github 上看到好多开源的 View 控件,如果涉及动画,基本上都使用的是功能更加强大的属性动画,真心觉得属性动画比之前的补间动画强大太多饿了,也学到了使用属性动画自定义 View 的方便和强大。所以想记录一下在自定义 View 时,使用属性动画的几个方面。

属性动画的强大之处在于可以对任意对象的任意属性增加动画效果,并且可以自定义值的类型和变化过程(TypeEvaluator)和过渡速度(Interpolator)。

这篇文章先来看看 ValueAnimator 的使用方法。

ValueAnimator

ValueAnimator 是属性动画的核心类,最常用的 ObjectAnimator (下篇会讲到)就是它的子类。此类只是以特定的方式(可以自定义)对值进行不断的修改,已达到某种想要的过渡效果。此类提供设置播放次数、动画间隔、重复模式、开始动画以及设置动画监听器的方法。

看一个最简单的例子吧。

ValueAnimator animator = ValueAnimator.ofFloat(0f, 1.0f);
animator.setDuration(3000);
animator.setInterpolator(new LinearInterpolator());
animator.start();

以上代码先使用 ofFloat() 方法接收 0 和 1 参数初始化了一个 ValueAnimator 对象,接着设置动画播放的时间,设置变化速率为系统提供的线性变化,最后启动动画。

达到的效果是,在3000毫秒内从0线性增加到1。我们试着打印出这些值。

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float value = (Float)animation.getAnimatedValue();
        Log.d(TAG, value);
    }
});
animator.start();

结果打印从0到1 线性 变化的值,并且耗时3000毫秒。如果我们不设置 Interpolator,会调用默认的 Interpolator,先加速增加后减速增加。

这些值对于动画有什么用呢?我们可以添加监听器获取每次改变的值,并且可以把此值用在改变 view 的某些属性上,从而达到动画效果。

怎样使用ValueAnimator自定义View动画?

当然,上面的代码只是对数字的变化的操作,并没有涉及到动画效果。接下来我们通过在动画开始前(start()方法)设置监听器来让自定义 View 做出相应的动画。

如果想要做出如下图所示的效果,使用 ValueAnimator 就特别简单。

valueanimator1
横向移动gif

由于效果是一个小球从左边移动一段距离后,重复执行。变化的值只有小球圆心的X轴坐标。所以可以利用 ValueAnimator 产生从开始位置到结束位置的一系列中间值,设置小球移动的动画。

直接上代码:
onDraw() 方法:根据 XPoint (x轴坐标)绘制圆形。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawCircle(XPoint, heightSpecSize / 2, 30, mPaint);
}

对外提供开始动画的 start() 方法:创建 ValueAnimator 对象,以及各种属性,添加监听器把每次改变的值赋值给 xPoint,并且通知 view 重绘,最后开始动画。

public void start() {
    final ValueAnimator animator = ValueAnimator.ofFloat(60, 600);
    animator.setDuration(2000);
    animator.setRepeatCount(ValueAnimator.INFINITE);
    animator.setRepeatMode(ValueAnimator.RESTART);
    animator.setInterpolator(new LinearInterpolator());
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            XPoint = (Float)animation.getAnimatedValue();
            invalidate();
        }
    });
    animator.start();
}

以上代码首先创建一个从 60 变化到 600 的 ValueAnimator 对象,接着设置动画时间、重播方式、重播次数和速度变化情况,最后增加监听器,每次获取变化的值再赋值给 xPoint ,接着很重要的一点,调用 invalidate() 方法通知 View 重绘,即值每次改变都需要 View 重绘。

这样就很方便的根据属性动画控制 float 值的改变,给 view 增加了动画的效果。

TypeEvaluator

前面的例子,创建 ValueAnimator 的时候,都是使用的 ValueAnimator.ofFloat(float, float) 方法,这个方法传递的参数为可变参数。其实创建 ValueAnimator 也可以使用 ofInt() 等方法,得到 Int 值得改变动画。
在使用 ofInt() 或 ofFloat() 方法时,其实是使用了 FloatEvaluator、FloatArrayEvaluator、IntEvaluator、IntArrayEvaluator 这些系统已经实现好了的 TypeEvaluator。我们使用这些方法创建 ValueAnimator 时就不必自定义类来继承 TypeEvaluator。

还有一个很重要的方法: ValueAnimator.ofObject(TypeEvaluator, Object...),此方法和其他方法不同之处在于参数 TypeEvaluator 和 Object,需要我们自己去实现,此处需要使用系统已经实现好的或自定义子类,用于设定自定义类型。

假如现在需要这个圆形像下图这样斜着移动,使用 ValueAnimator 该怎样实现?当然很很多简单的实现方法,比如 Path 路径的使用,这里为了演示自定义 TypeEvaluator,使用自定义 TypeEvaluator 的方式来实现。

valueanimator2

斜着移动gif

自定义类 PointEvaluator 实现 TypeEvaluator 接口。

class PointEvaluator implements TypeEvaluator{

    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        Point startPoint = (Point) startValue;
        Point endPoint = (Point) endValue;

        int x = (int) (startPoint.x + fraction * (endPoint.x - startPoint.x));
        int y = (int) (startPoint.y + fraction * (endPoint.y - startPoint.y));
            
        return new Point(x, y);
    }
}

这里需要实现 evaluate() 方法,根据动画完成的百分比返回对应的值。其中 fraction 参数和动画时间有关,一般代表动画执行的完成程度,比如动画总时间为 2000 毫秒,现在执行了1000 毫秒,那么此刻传递进来的 fraction 参数值为二分之一。

在 onDraw() 方法中依然还是简单的绘制一个圆形,此圆的圆心坐标是成员变量 mPoint 的 x , y值。

protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawCircle(mPoint.x, mPoint.y, 30, mPaint);
}

最后提供 start() 方法开始动画。

public void start() {
    final ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), 
        new Point(30, 30), new Point(600, 600));
    animator.setDuration(2000);
    animator.setRepeatCount(ValueAnimator.INFINITE);
    animator.setRepeatMode(ValueAnimator.REVERSE);
    animator.setInterpolator(new LinearInterpolator());
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mPoint = (Point)animation.getAnimatedValue();
            invalidate();
        }
    });
    animator.start();
}

和上边的代码类似,只是 ValueAnimotor 操作的值从 float 改变成了 Point (可以自定义类型),不再做过多的解释了。

这个例子,我们可以知道 ValueAnimotor 操作的值的类型是任意的,可以由我们来自定义,只要自定义类实现 TypeEvaluatorb,并且实现此接口的唯一一个方法 evaluate() 即可。

TimeInterpolator

TimeInterpolator 表示动画的速率,上边代码中我们就设置了动画速率,只不过使用的是API中已经实现好了的 LinearInterpolator。

查询API知道 TimeInterpolator 接口有很多已知的实现类,比如
AccelerateDecelerateInterpolator 表示先加速后减速,
AccelerateInterpolator 表示一直加速,
DecelerateInterpolator 表示一直加速等。
BounceInterpolator 可以模拟物理规律,实现反弹的效果

如果不设置 setInterpolator(),那么默认使用 AccelerateDecelerateInterpolator。

在自定义 TimeInterpolator 之前,我们先看看API中提供的实现的例子:LinearInterpolator,AccelerateInterpolator。

TimeInterpolator 接口,只有一个方法:getInterpolation(float input),此方法接收一个 float 类型的 input 值,此值的变化范围为0~1,并且根据动画运行的时间,均匀增加,和 TypeEvaluator 接口方法中的参数 fraction 很像, fraction 也是根据动画运行的时间,均匀增加。

注意:getInterpolation() 方法的返回值传递给了 TypeEvaluator 的 fraction 参数

LinearInterpolator 源码:

public float getInterpolation(float input) {
    return input;
}

从源码中,可以看到 getInterpolation 的逻辑简单到不能再简单,直接返回 input,因为 input 本身表示的就是均匀增加的。

AccelerateInterpolator 源码:

public float getInterpolation(float input) {
    if (mFactor == 1.0f) {
        return input * input;
    } else {
        return (float)Math.pow(input, mDoubleFactor);
    }
}

构造函数接收一个 mFactor 表示加速的倍数,接收1.0f以上的数,mDoubleFactor = 2 * mFactor
在 getInterpolation() 方法中,判断 mFactor 如果等于1.0f,直接返回 input * input(默认,二次函数增长),否则返回 input 的 mDoubleFactor 次方(mDoubleFactor 次函数增长)。

看来要想实现一个自定义的 TimeInterpolator,得要有一些必要的数学修养了。没办法,数学没有那么好,只能实现一个简单的 TimeInterpolator,演示自定义 TimeInterpolator 的步骤。

注意:最好让 getInterpolation() 方法返回的值在0~1之间,并且递增。以便在使用fraction参数时意思明确

下面我们实现一个以10给底数的负指数函数减速的例子:

    class LgDecelerateInterpolator implements TimeInterpolator {

        private float background;

        public LgDecelerateInterpolator() {
            background = 10;
        }

        @Override
        public float getInterpolation(float input) {
            return (1 - (float) Math.pow(background, -input));
        }
    }

然后在设置 animator.setInterpolator(new LgDecelerateInterpolator());,就可以使用了。

成员变量 background 表示底数,在构造方法中初始化为 10,因为是减速,所以用到了负指数,得到的值从 1 变化到 0 ,所以再用1减去这个结果值,就得到了最终的结果。

AnimatorSet

AnimatorSet 表示动画的集合,可以把几个动画一起播放,或按次序播放。提供 paly、with、after 等方法。

接下来,把以上用到的全部结合起来,播放一个动画的效果:圆形从 View 的左上角移动到右下角,伴随着颜色的变化,移动速度和颜色变化的速率都由上面自定义的 LgDecelerateInterpolator 实现。

效果图:

valueanimator3

斜着指数减速移动伴随颜色指数渐变 gif

完整的代码:

public class MyView extends View {

    private Paint mPaint;
    private Point mPoint;
    private int mColor;

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPaint();
    }

    public MyView(Context context) {
        super(context);
        initPaint();
    }

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setColor(0xFFF00000);
        mPaint.setAntiAlias(true); // 抗锯齿
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(mPoint.x, mPoint.y, 60, mPaint);
    }

    public void start() {
        final ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(),
                new Point(60, 60), new Point(990, 1050));
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mPoint = (Point) animation.getAnimatedValue();
                invalidate();
            }
        });

        final ValueAnimator animator1 = ValueAnimator.ofArgb(0xFFF00000,0xFFFFFF00);
        animator1.setRepeatCount(ValueAnimator.INFINITE);
        animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mColor = (int) animation.getAnimatedValue();
                mPaint.setColor(mColor);
            }
        });

        AnimatorSet animationSet = new AnimatorSet();
        animationSet.setDuration(3000);
        animationSet.setInterpolator(new LgDecelerateInterpolator());

        animationSet.play(animator).with(animator1);
        animationSet.start();
    }

    class PointEvaluator implements TypeEvaluator {

        @Override
        public Object evaluate(float fraction, Object startValue, Object endValue) {
            Point startPoint = (Point) startValue;
            Point endPoint = (Point) endValue;

            int x = (int) (startPoint.x + fraction * (endPoint.x - startPoint.x));
            int y = (int) (startPoint.y + fraction * (endPoint.y - startPoint.y));

            return new Point(x, y);
        }
    }

    class LgDecelerateInterpolator implements TimeInterpolator {

        private float background;
        public LgDecelerateInterpolator() {
            background = 10;
        }

        @Override
        public float getInterpolation(float input) {
            return (1 - (float) Math.pow(background, -input));
        }
    }

}

start() 方法中创建了两个 ValueAnimator,第一个使用 ofObject() 方法,使用自定义的 PointEvaluator,第二个使用API已经实现的ofArgb 使颜色值变化的动画属性(API21以上支持),都添加监听器以实现对成员变量的修改,重绘 View,最后创建 AnimatorSet 对两个动画进行叠加,在播放移动动画的同时播放颜色渐变的动画。

两种方法限制 EditText 最多输入两位小数

版权声明:本文为 Bakumon 原创文章,转载需在明确位置注明出处!!!#10


测试又提 EditText 输入限制的 bug 🐛 了,这次是和小数点有关的。

bug:需要限制 EditText 最多输入两位小数。

🤕

事情是这样的,app 中新增信息中有一栏需要输入投资额,单位是万元,对于这种 EditText 我想都不用想直接用小数键盘就 OK 啊。
android:inputType="numberDecimal"

可是问题来了,测试输入了一个特别大的数,类似于 123456789987654321 ,接口直接报了 400 (客户端错误),说明客户端提交的参数不符合服务器设定的参数类型。

WTF! 这显然不是 App 的 bug 啊!
“去找后台吧”,又一次给了测试这个感人的建议。

出现转折了,后台说他解决不了,[黑人问号脸].jpg

后来测试说限制一下输入的位数就行,因为 9 位以下是没问题的,虽然不是解决问题的方法,但是没办法,谁让后台不给力呢,于是出现了这个 EditText 只能输入 9 位的小数数字。
android:maxLength="9"


以上纯属扯蛋,请自行忽略。

后来客户提出要求,这个输入框限制最多输入两位小数吧。于是就有了文章开头的 bug 🐛 。

细节要求:

  1. 以小数点开头,前面自动加上 "0"
  2. 以小数点结尾,去掉小数点

下面有两种方法分别实现:

一、添加 TextChangedListener 输入监听

思路:利用 EditText 的输入监听实现小数位的截取,和移动光标到末尾,在失去焦点后,去掉结尾的小数点。

添加输入监听:

editText.addTextChangedListener(new TextWatcher() {
    boolean deleteLastChar;// 是否需要删除末尾

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (s.toString().contains(".")) {
            // 如果点后面有超过三位数值,则删掉最后一位
            int length = s.length() - s.toString().lastIndexOf(".");
            // 说明后面有三位数值
            deleteLastChar = length >= 4;
        }
    }

    @Override
    public void afterTextChanged(Editable s) {
        if (s == null) {
            return;
        }
        if (deleteLastChar) {
            // 设置新的截取的字符串
            editText.setText(s.toString().substring(0, s.toString().length() - 1));
            // 光标强制到末尾
            editText.setSelection(editText.getText().length());
        }
        // 以小数点开头,前面自动加上 "0"
        if (s.toString().startsWith(".")) {
            editText.setText("0" + s);
            editText.setSelection(editText.getText().length());
        }
    }
});

添加失去焦点监听:

editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        EditText editText1 = (EditText) v;
        // 以小数点结尾,去掉小数点
        if (!hasFocus && editText1.getText() != null && editText1.getText().toString().endsWith(".")) {
            editText.setText(editText1.getText().subSequence(0, editText1.getText().length() - 1));
            editText.setSelection(editText.getText().length());
        }
    }
});

封装在了一个单例类中,点击下面链接查看完整代码:
代码Gist (Gist需科学上网)

二、设置 InputFiler

自定义底部 Dialog——宽度充满屏幕

版权声明:本文为 Bakumon 原创文章,转载需在明确位置注明出处!!!#3


在自定义底部选择省市区的 Dialog 时,可能会遇到这几个问题:

  1. 根据一般的 Dialog 布局的话,Dialog 会 show 在屏幕中间
  2. 跟布局使用宽高 match_parent,把主要布局放在最下面,上面空白部分用 View 填充,这样布局虽然放在最下面了,但是两边有去不掉的边距
  3. 设置 style 为全屏,可以去掉两边的边距,但是状态栏的颜色没有变化,强迫症受不了

完美的方案是利用 WindowManager 设置 Dialog 的布局和入场动画。

dialog

1.定义 style

定义自定义 Dialog 通用的 style

<!-- Dialog style-->
<style name="Theme.Light.NoTitle.Dialog" parent="@android:style/Theme.Dialog">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:windowFrame">@null</item>
</style>

2.Dialog 进入离开动画(可选)

<!-- 底部 dialog 进入离开动画 -->
<style name="Animation.Bottom" parent="@android:style/Animation">
    <item name="android:windowEnterAnimation">@anim/bottom_up_in</item>
    <item name="android:windowExitAnimation">@anim/bottom_down_out</item>
</style>

/res/anim/bottom_up_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@android:interpolator/accelerate_decelerate">
    <translate
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromYDelta="100%p"
        android:toYDelta="0"/>
    <alpha
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromAlpha="0.95"
        android:toAlpha="1"/>
</set>

/res/anim/bottom_down_out.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromYDelta="0"
        android:toYDelta="100%p" />
    <alpha
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromAlpha="1"
        android:toAlpha="0.95" />
</set>

3.Dialog 构造器

public ChooseAddressDialog(Context context) {
    super(context, R.style.Theme_Light_NoTitle_Dialog);
    mContext = context;
    View view = LayoutInflater.from(context).inflate(R.layout.dialog, null);
    this.setContentView(view);
    // 设置 dialog 位于屏幕底部,并且设置出入动画
    setBottomLayout();
}

4.WindowManager 设置布局

/**
* 设置 dialog 位于屏幕底部,并且设置出入动画
*/
private void setBottomLayout() {
    Window win = getWindow();
    if (win != null) {
        win.getDecorView().setPadding(0, 0, 0, 0);
        WindowManager.LayoutParams lp = win.getAttributes();
        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
        win.setAttributes(lp);
        // dialog 布局位于底部
        win.setGravity(Gravity.BOTTOM);
        // 设置进出场动画
        win.setWindowAnimations(R.style.Animation_Bottom);
    }
}

为什么说 JavaScript 是单线程异步的?

版权声明:本文为 Bakumon 原创文章,转载需在明确位置注明出处!!!#12


最近在廖老师那学习 JavaScript,学到 Node.js 部分 注意到了这样一句话:

因为 JavaScript 是单线程执行,根本不能进行同步IO操作,所以,JavaScript的这一“缺陷”导致了它只能使用异步IO。

意思不就是说 JavaScript 是单线程执行的,但是却可以进行异步操作。

看起来很矛盾好吗。黑人问号脸.jpeg

其实这句话是这样理解的:

  1. JavaScript 的确是单线程的
  2. 异步是 浏览器的 JavaScript 引擎做的工作
console.log('开始');

$.ajax('/api/categories', {
    dataType: 'json'
}).done(function (data) {
    console.log('成功, 收到的数据: ' + JSON.stringify(data));
}).fail(function (xhr, status) {
    console.log('失败: ' + xhr.status + ', 原因: ' + status);
});

console.log('结束');

以上代码执行结果是:开始 ---> 结束 ---> 成功, 收到的数据: ...(假设请求成功)
而不是:开始 ---> 成功, 收到的数据: ...(假设请求成功) ---> 结束

说明 JavaScript 确实异步执行了 AJAX 的回调方法。

理解:
JavaScript 是单线程的,说明代码只能按照执行顺序一行一行执行,遇到耗时代码就会阻塞住(不能像其他语言一样开一个线程来执行耗时操作),然而浏览器是事件驱动的,很多操作是异步的,浏览器有多个线程来做此工作,js 中的异步代码如 AJAX 完成请求、 setTimeout() 定时器到时间后,浏览器会把这些需要执行的异步操作放到自己的消息队列中,并轮循这个队列,在浏览器空闲时处理事件。

Ubuntu 上常用的软件、工具以及主题推荐

版权声明:本文为 Bakumon 原创文章,转载需在明确位置注明出处!!!#5


记录一下自己在 Ubuntu 16.04 上用到的软件。包括常用软件、好用的工具和主题,不定期更新。

主要软件

1. weChat 微信

安装微信网页版,有 Mac 和 Linux 版本,项目地址
下载32或64位版本 linux-x64.tar.gzlinux-ia32.tar.gz,解压到任意目录。
打开终端执行

./electronic-wechat

即可打开微信,右键 Dash 上的微信图标,选择锁定到启动器,方便下次启动。

2. 网易云音乐

网易出品,必属精品。

下载地址,下载 Ubuntu 对应版本的 deb 文件,双击或使用 dpkg -i ?.deb 命令 安装即可。

如果安装报缺少依赖的错误,使用以下命令解决依赖后重新安装即可。

sudo apt-get install -f

3. VS Code

VS Code 相对 Atom、Sublime Text,较轻量。下载地址,下载 .deb 文件双击安装即可。

VS Code 默认支持 Git、Markdown 预览,也有很多插件。

小而美的工具

1. Gpick 屏幕取色器

安装非常简单:

sudo apt-get install gpick

Gpick 很强大,不过我只是使用它来进行屏幕取色,开发时从 UI 上进行简单的取色,只需要把鼠标悬浮在取色区,按空格即可,每按一次,保存一个色值。可以查看多种不同的颜色类型。
下图是我使用 Gpick 获取 Google 主页上各个字母色值的截图。

gpick

2. Srceen Ruler 屏幕标尺

安装同样很简单:

sudo apt-get install screenruler

支持 6 种常见单位,可旋转。

srceenruler

3. shadowsocks-Qt5

科学上网必备

sudo add-apt-repository ppa:hzwhuang/ss-qt5

sudo apt-get update

sudo apt-get install shadowsocks-qt5

Note:连接好 shadowsocks 后,需要在系统设置-->网络 里设置手动代理,在 socks 那栏填上 127.0.0.1 ,端口为ss账号设置的本地端口,一般为1080,才能用浏览器科学上网。

Chrome 浏览器不需要额外的设置,火狐浏览器还需要在设置为使用系统代理。另外,设置了手动网络 socks 代理后,终端就没有网络链接了,因为终端走的是 http ,而不是 socks。

主题和图标

安装搜索结果 Unity Tweak Tool 更方便设置主题和图标

sudo apt-get install unity-tweak-tool 

1. Arc 主题

github 地址(含安装方法): https://github.com/horst3180/arc-theme

该主题是我一直在使用的主题,分为 Arc 、Arc-darker 和 Arc-dark 色调。

我使用的是 Arc-dark 最暗的色调。

安装方法:

这里使用 ppa 源安装,也可以去 项目的README 查看编译源码安装

sudo add-apt-repository ppa:noobslab/themes

sudo apt-get update

sudo apt-get install arc-theme

2.Numix 图标

github 地址(含安装方法): https://github.com/numixproject/numix-gtk-theme

其实 Numix 是主题,不过我喜欢用它的圆形图标,常用的软件基本都适配了,细节中见设计。

安装方法:

这里使用 ppa 源安装,也可以去 项目的README 查看编译源码安装

sudo add-apt-repository ppa:numix/ppa

sudo apt-get update

sudo apt-get install numix-gtk-theme numix-icon-theme-circle

使用 ColorStateList 动态改变控件背景色 

版权声明:本文为 Bakumon 原创文章,转载需在明确位置注明出处!!!#2


年关将至,项目也不那么急了,也有了大把的时间,所以在做一个 Gank.io 的客户端,为这个客户端最多的网站再添一个属于我的客户端,主要是为了熟悉目前最流行的框架,Rxjava、Retrofit2、和 MVP 模式,再就是认认真真的做一个自己满意:+1:的 Gank.io 客户端

本文记录动态改变新控件背景等颜色的方法。

在做首页时突然想到可以使用支持库中的 Palette (调色板)从加载的 Banner 妹子图中取颜色设置到项目中所有的控件,以达到自动动态改变主题色的效果。

于是找到了这个强大好用的开源库 GlidePalette,这个库可以在使用 Glide 加载图片时获取到图片调色板的颜色值,于是解决了获取网络图片调色板的问题,接下来就是动态改变各个控件背景色了。

PS: PicassoPalette 这是 GlidePalette 的 Picasso 版本。

ColorStateList

ColorStateList 类用于构建不同状态下控件对应的颜色,对,和 xml 文件中常写的 selector 的作用是一样的,区别在于 selector 是静态的,不能动态改变控件的颜色,需要在 java 代码中动态改变控件各个状态下的颜色,就要用到 ColorStateList

使用 ColorStateList 也很简单,用构造方法创建一个 ColorStateList 对象,再使用控件对应的方法设置即可。

栗子:

// 颜色数组
int[] colors = new int[]{color, color1, color2, color3, color4, color5};

// 颜色数组对应的状态
int[][] states = new int[6][];
states[0] = new int[]{android.R.attr.state_checked, android.R.attr.state_enabled};
states[1] = new int[]{android.R.attr.state_enabled, android.R.attr.state_focused};
states[2] = new int[]{android.R.attr.state_enabled};
states[3] = new int[]{android.R.attr.state_focused};
states[4] = new int[]{android.R.attr.state_window_focused};
states[5] = new int[]{};

switchCompat.setThumbTintList(new ColorStateList(states, colors));

可以看到,ColorStateList 构造方法需要传递两个数组 states、colors,对应控件的状态和状态下的颜色,状态数组是一个二维数组,可以把两个及以上的状态放在一个状态数组中,方便设置相同的颜色值。

神奇的 Drawable 文件夹——栗子篇

版权声明:本文为 Bakumon 原创文章,转载需在明确位置注明出处!!!#7


废话不多说,直接上栗子。

1.小红点

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="oval">
    <solid android:color="#F2601F"/>
    <size
        android:width="20dp"
        android:height="20dp"/>
</shape>

2.纯色圆角选择器

如果设置禁用状态,需要放在按下等状态的前面,否则不起作用,因为系统会从上到下一次解析,遇到合适的状态就直接取值,不会再解析后面的节点。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 禁用状态 -->
    <item android:state_enabled="false">
        <shape>
            <corners android:radius="8dp"/>
            <solid android:color="#A0A0A0"/>
        </shape>
    </item>
    <!-- 按下状态 -->
    <item android:state_pressed="true">
        <shape>
            <corners android:radius="8dp"/>
            <solid android:color="#f58104"/>
        </shape>
    </item>
    <!-- 正常状态 -->
    <item android:state_pressed="false">
        <shape>
            <corners android:radius="8dp"/>
            <solid android:color="#F89E3D"/>
        </shape>
    </item>
</selector>

3.圆角边框选择器

设置圆角边框背景的时候,需要透明化中间部分,否则在低版本手机上,会表现成黑色背景。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape>
            <stroke android:width="1dp" android:color="#A0A0A0"/>
            <corners android:radius="8dp"/>
            <!-- 中间部分背景透明 --> 
            <solid android:color="#00000000"/>
        </shape>
    </item>
    <item android:state_pressed="false">
        <shape>
            <stroke android:width="1dp" android:color="@color/colorAccent"/>
            <corners android:radius="8dp"/>
            <!-- 中间部分背景透明 --> 
            <solid android:color="#00000000"/>
        </shape>
    </item>
</selector>

4.文字颜色选择器

在项目 src/main/res 目录下,新建 color 资源文件夹,并在 /color 下新建 selector_text_color.xml 文件。这样就可以在设置控件的 android:textColor 属性时引用此选择器,控制控件被选中或者取消选中时文本的颜色改变。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#FFFFFF" android:state_selected="true"/>
    <item android:color="#FB4A41" android:state_selected="false"/>
</selector>

5.波纹点击效果

要实现在 5.0 以上手机上点击出现波纹效果,5.0 以下单纯变灰的效果,有两种方法:

第一种:自定义两个相同名称的 selector ,分别放在 drawabledrawable-v21 区别开 21 版本之前和之后

drawable/selector_bg.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <color android:color="#F2F2F2" />
    </item>
    <item android:state_pressed="false">
        <color android:color="@color/white" />
    </item>
</selector>

drawable-v21/selector_bg.xml:

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="#F2F2F2">
    <!-- 有界 -->
    <!-- 无界去掉 id 属性即可 -->
    <item
        android:id="@android:id/mask"
        android:drawable="@color/gray"/>
</ripple>

然后在 View 上设置:

android:clickable="true"
android:background="@drawable/selector_bg"

第二种:直接使用系统提供的 attr

android:clickable="true"
<!-- 有界 -->
android:background="?attr/selectableItemBackground"
<!-- 无界 -->
android:background="?attr/selectableItemBackgroundBorderless"

Note:有的控件需要设置 android:foreground 前景属性,比如 CardView

两种方式对比:

  1. 使用系统提供的 attr,简单方便,不用考虑配色等问题,便于和系统风格统一,
  2. 使用自定义 selector 的方式,比较灵活,可以根据需求改变波纹颜色,自定义形状等

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.