Dino's blog

Life is made up of small pleasures


  • 首页

  • 关于

  • 归档

  • 标签

  • 搜索
close

vector动画以及兼容

发表于 2016-10-06   |     |   阅读次数

之前讲过了用静态的Vector,这里讲一下使用动画,这里就直接使用支持包了

1.引用com.android.support:appcompat-v7:23.2.0以上的包

2.在build中defaultConfig{}里面写vectorDrawables.useSupportLibrary = true

上面两步和使用静态vector要求一样
下面开始就是使用动画的步骤

1.新建vector静态文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="256dp"
android:viewportHeight="70"
android:viewportWidth="70">
<path
android:name="heart1"
android:pathData="..."
android:strokeColor="#E91E63"
android:strokeWidth="1"
/>
<path
android:name="heart2"
android:pathData="..."
android:strokeColor="#E91E63"
android:strokeWidth="1"
/>
</vector>

2.新建动画文件

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="6000"
android:propertyName="trimPathEnd"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"/>

3.新建Animated-Vector图像

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_android_black_24dp">
<target
android:name="heart1"
android:animation="@animator/path_animator"/>
<target
android:name="heart2"
android:animation="@animator/path_animator"/>
</animated-vector>

4.在布局文件引用Animated-Vector图像

1
2
3
4
5
<android.support.v7.widget.AppCompatImageView
android:id="@+id/aaaa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/v_animation"/>

5.在代码中启动动画

1
2
3
4
5
AppCompatImageView imageView = (AppCompatImageView)findViewById(R.id.aaaa);
Drawable animation = imageView.getDrawable();
if (animation instanceof Animatable) {
((Animatable) animation).start();
}

完整代码可以可以查看github

附上两个图标库
iconfont
easyicon

还有svg在线转vector

Android如何使用Vector(矢量图)以及兼容旧版本

发表于 2016-09-29   |     |   阅读次数

这段时间忙成狗,天天加班,昨天凌晨一点多下班,都没时间写东西了,今天中午抽个空记录下Vector兼容旧版本的问题
Android 5.0发布的时候,Google提供了Vector的支持。Vector Drawable相对于普通的Drawable来说,有以下几个好处:

1.Vector图像可以自动进行适配,不需要通过分辨率来设置不同的图片,

2.Vector图像可以大幅减少图像的体积,同样一张图,用Vector来实现,可能只有PNG的几十分之一 使用简单,

3.很多设计工具,都可以直接导出SVG图像,从而转换成Vector图像 功能强大,不用写很多代码就可以实现非常复杂的动画 成熟、稳定,前端已经非常广泛的进行使用了

Vector图像刚发布的时候,是只支持Android 5.0+的,对于Android pre-L的系统来说,并不能使用,所以,可以说那时候的Vector并没有什么卵用。
不过自从AppCompat 23.2之后,Google对p-View的Android系统也进行了兼容,也就是说,Vector可以使用于Android 2.1以上的所有系统,
只需要引用com.android.support:appcompat-v7:23.2.0以上的版本就可以了。

兼容版本需要做以下三步:

1.引用com.android.support:appcompat-v7:23.2.0以上的包

2.在build中defaultConfig{}里面写vectorDrawables.useSupportLibrary = true

3.使用app:srcCompat替换android:src

不过 app:srcCompat 支持ImageView\ImageButton

Button并不能直接使用app:srcCompat来使用Vector图像,需要通过Selector来进行使用,首先,创建两个图像,用于Selector的两个状态

select1.xml

1
2
3
4
<code class="hljs xml"><vector android:height="24dp" android:viewportheight="24.0" android:viewportwidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillcolor="#FF000000" android:pathdata="M14.59,8L12,10.59 9.41,8 8,9.41 10.59,12 8,14.59 9.41,16 12,13.41 14.59,16 16,14.59 13.41,12 16,9.41 14.59,8zM12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z">
</path></vector>
</code>

select2.xml

1
2
3
4
<code class="hljs xml"><vector android:height="24dp" android:viewportheight="24.0" android:viewportwidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillcolor="#FF000000" android:pathdata="M11,15h2v2h-2zM11,7h2v6h-2zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z">
</path></vector>
</code>

selector.xml

1
2
3
4
5
<code class="hljs xml"><!--?xml version="1.0" encoding="utf-8"?-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/selector1" android:state_pressed="true">
<item android:drawable="@drawable/selector2">
</item></item></selector></code>

button

1
<button android:background="@drawable/selector" android:id="@+id/btn" android:layout_height="70dp" android:layout_width="70dp"></button>

然后运行,你会发现。。依然不行
需要在activity里面加上

1
2
3
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

开启这个flag后,你就可以正常使用Selector这样的DrawableContainers了。
同时,你还开启了类似android:drawableLeft这样的compound drawable的使用权限,以及RadioButton的使用权限,以及ImageView’s src属性。

Radiobutton同样可以

1
<radiobutton android:button="@drawable/selector" android:layout_height="50dp" android:layout_width="50dp"></radiobutton>

还有动态Vector等会再另起一篇好了

制作gif

发表于 2016-08-26   |     |   阅读次数

看到github上演示效果都用的gif,我也去网上找了很多方法,格式工厂之类的都是视频转gif,使用起来感觉效果很差,还有转换失败的情况,转出来的比原视频还大。
最后找到一款炒鸡好用的软件,点击LICEcap,直接去官网下吧,
可以直接录制屏幕保存为gif

实现自定义banner

发表于 2016-08-25   |     |   阅读次数

要做一个不停滚动的通知,类似banner,由于比较简单的功能,这里就没有用banner的框架,自己简单实现封装了下,最开始用的TimerTask,一开始用的挺正常的,可是放置时间久了后后界面就乱了。。。于是看了下开源banner框架的源码,别人用Handler postDelayed实现的。。。于是改改改,测试了下正常了,应该是线程的问题,暂时还不明白具体原因。

1.用TimerTask实现的乱掉的界面如图

1

2.用Handler实现的,如图

2

2.1代码很简单,这里只做了简单的封装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import android.content.Context;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.RelativeLayout;
import com.tyky.edu.teacher.R;
import java.util.List;
/**
* Created by Dino on 8/25 0025.
*/
public class NewNoticeBanner {
private TranslateAnimation mShowAction;
private TranslateAnimation mHiddenAction;
private Context context;
private int count =0;
private ViewGroup parentView;
private List<View> views;
private boolean turning = false;
private long autoTurningTime;
private RelativeLayout rlNodata;
private Handler timeHandler = new Handler();
private Runnable adSwitchTask = new Runnable() {
@Override
public void run() {
if (parentView != null && turning) {
View view = parentView.getChildAt(0);
if(view!=null){
view.setVisibility(View.GONE);
view.startAnimation(mHiddenAction);
}
parentView.removeAllViews();
if(count<=views.size()-1){
parentView.addView(views.get(count));
}else{
count=0;
parentView.addView(views.get(count));
}
views.get(count).setVisibility(View.VISIBLE);
views.get(count).startAnimation(mShowAction);
count++;
timeHandler.postDelayed(adSwitchTask, autoTurningTime);
}
}
};
private static class Holder{
static NewNoticeBanner INSTANCE = new NewNoticeBanner();
}
public static synchronized NewNoticeBanner getInstance() {
return NewNoticeBanner.Holder.INSTANCE;
}
public NewNoticeBanner init(Context context,ViewGroup parentView){
this.parentView = parentView;
this.context = context;
//初始化动画
mShowAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF,
2.0f,Animation.RELATIVE_TO_SELF, 0.0f);
mShowAction.setDuration(500);
mHiddenAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF,-1.0f);
mHiddenAction.setDuration(500);
//初始化无数据布局
rlNodata = (RelativeLayout) LayoutInflater.from(context).inflate(R.layout.new_notice_nodata,null);
return this;
}
public NewNoticeBanner initViews(List<View> views){
this.views = views;
if(views==null||views.size()==0){
parentView.removeAllViews();
parentView.addView(rlNodata);
}else if(views.size()==1){
parentView.removeAllViews();
parentView.addView(views.get(0));
}
return this;
}
public void startTurning(long autoTurningTime) {
if(views!=null&&views.size()>1) {
//如果是正在翻页的话先停掉
if (turning) {
stopTurning();
}
turning = true;
this.autoTurningTime = autoTurningTime;
timeHandler.postDelayed(adSwitchTask, autoTurningTime);
}
}
public void stopTurning() {
turning = false;
timeHandler.removeCallbacks(adSwitchTask);
}
}
2.2在activity里面调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
private void initNoticeBanner(){
new Thread(new Runnable() {
@Override
public void run() {
getNewNotice();//查询数据库,然后新建子view
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
newNoticeBanner = NewNoticeBanner.getInstance().init(getActivity(),noticeRl).initViews(noticeViews);
onResume();
}
});
}
}).start();
}
@Override
public void onStop() {
super.onStop();
stopBanner();
}
@Override
public void onDestroy() {
super.onDestroy();
stopBanner();
}
@Override
public void onResume() {
super.onResume();
startBanner();
}
private void startBanner(){
if(newNoticeBanner!=null){
newNoticeBanner.startTurning(3000);
}
}
private void stopBanner(){
if(newNoticeBanner!=null){
newNoticeBanner.stopTurning();
}
}

由于数据库操作比较重,查询数据的地方最好写在子线程里,在后台运行或者跳到其他页面也要记得stop

仿ios下载控件

发表于 2016-08-24   |     |   阅读次数

仿着做了个类似ios appstore下载按钮
效果图如下:
2

1.创建自定义view

代码中注释写的很全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import com.tyky.edu.teacher.R;
/**
* Created by Dino on 8/18 0018.
*/
public class DownloadProgress extends View{
private int statue;
public static final int downloadStatue = 0;
public static final int progressStatue = 1;
public static final int finishStatue = 2;
private int width;// 控件的宽度
private int height;// 控件的高度
private int radius;// 圆形的半径
private int socktwidth = dp2px(2);// 圆环进度条的宽度
private Paint paint = new Paint();
private int progress = 70;// 百分比0~100;
private int textSize = dp2px(10);// 文字大小
private Bitmap bitmap;
@Deprecated
float scale = 0.35f;// 中间背景图片相对圆环的大小的比例
private int preColor = Color.parseColor("#ffffff");// 进度条未完成的颜色
private int progressColor = Color.parseColor("#2DB6E6");// 进度条颜色
private float paddingscale = 0.8f;// 控件内偏距占空间本身的比例
private int CircleColor = Color.parseColor("#ffffff");// 圆中间的背景颜色
private int textColor = progressColor;// 文字颜色
private onProgressListener monProgress;// 进度时间监听
private int startAngle = 270;
RectF rectf = new RectF();
private Bitmap bitmpre;
private int whiteColor = Color.parseColor("#ffffff");// 矩形中间的背景颜色
public DownloadProgress(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DownloadProgress);
statue = a.getInteger(R.styleable.DownloadProgress_statue, 0);// 默认0
bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.square);
bitmpre = BitmapFactory.decodeResource(getResources(),R.drawable.download_pre);
width = bitmpre.getWidth();
height = bitmpre.getHeight();
}
public DownloadProgress(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int reWidth;
int reHeight;
if (widthMode == MeasureSpec.EXACTLY)
{
reWidth = widthSize;
} else
{
int desired = (int) (getPaddingLeft() + width + getPaddingRight());
reWidth = desired;
}
if (heightMode == MeasureSpec.EXACTLY)
{
reHeight = heightSize;
} else
{
int desired = (int) (getPaddingTop() + height + getPaddingBottom());
reHeight = desired;
}
setMeasuredDimension(reWidth, reHeight);
}
@Override
protected void onDraw(Canvas canvas) {
switch (statue){
case downloadStatue:
drawDownload(canvas);
break;
case progressStatue:
drawProgress(canvas);
break;
case finishStatue:
drawOpen(canvas);
break;
}
super.onDraw(canvas);
}
private void drawDownload(Canvas canvas){
//图片缩小显示
int scalse = 5;
Rect srcRect = new Rect(0,0,width,height);
Rect dstRect = new Rect(width/scalse,height/scalse,width/scalse,height/scalse);
canvas.drawBitmap(bitmpre,0,0,paint);
canvas.drawBitmap(bitmpre,srcRect,dstRect,paint);
}
private void drawOpen(Canvas canvas){
int border = 1;
int h = bitmpre.getHeight()/2;
RectF outRect = new RectF(0, h/2,width, h/2+h);
RectF inRect = new RectF(border,h/2+border,width-border,h/2+h-border);
paint.setAntiAlias(true);
paint.setColor(progressColor);
// 绘制外矩形
canvas.drawRoundRect(outRect,5,5, paint);
paint.setColor(whiteColor);
// 绘制内矩形
canvas.drawRoundRect(inRect,5,5, paint);
String v ="打开";
paint.setColor(textColor);
paint.setTextSize(textSize);
// 绘制中间文字
Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
int baseline = ((int)(inRect.bottom + inRect.top) - fontMetrics.bottom - fontMetrics.top) / 2;
// 下面这行是实现水平居中,drawText对应改为传入targetRect.centerX()
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(v, inRect.centerX(), baseline, paint);
}
private void drawProgress(Canvas canvas){
int size = height;
if (height > width)
size = width;
radius = (int) (size * paddingscale / 2f);
paint.setAntiAlias(true);
paint.setColor(progressColor);
canvas.drawCircle(width / 2, height / 2, radius+2, paint);//画最外面的边线
paint.setColor(preColor);
// 绘制最大的圆 进度条圆环的背景颜色(未走到的进度)就是这个哦
canvas.drawCircle(width / 2, height / 2, radius, paint);
rectf.set((width - radius * 2) / 2f, (height - radius * 2) / 2f,
((width - radius * 2) / 2f) + (2 * radius),
((height - radius * 2) / 2f) + (2 * radius));
paint.setColor(progressColor);
canvas.drawArc(rectf, startAngle, progress * 3.6f, true, paint);
paint.setColor(CircleColor);
// 绘制用于遮住伞形两个边的小圆
canvas.drawCircle(width / 2, height / 2, radius - socktwidth, paint);
if (bitmap != null) {// 绘制中间的图片
int width2 = (int) (rectf.width() * scale);
int height2 = (int) (rectf.height() * scale);
rectf.set(rectf.left + width2, rectf.top + height2, rectf.right
- width2, rectf.bottom - height2);
canvas.drawBitmap(bitmap, null, rectf, null);
}
}
public int dp2px(int dp) {
return (int) ((getResources().getDisplayMetrics().density * dp) + 0.5);
}
/**
* 设置进度
*
* @param progress
* <p>
* ps: 百分比 0~100;
*/
public void setProgress(int progress) {
if (progress > 100)
return;
this.progress = progress;
invalidate();
if (monProgress != null)
monProgress.onProgress(progress);
}
/**
* 设置状态
*
*/
public void setStatue(int statue) {
this.statue = statue;
invalidate();
}
/**
* 设置圆环进度条的宽度 px
*/
public DownloadProgress setProdressWidth(int width) {
this.socktwidth = width;
return this;
}
/**
* 设置文字大小
*
* @param value
*/
public DownloadProgress setTextSize(int value) {
textSize = value;
return this;
}
/**
* 设置文字大小
*
*/
public DownloadProgress setTextColor(int color) {
this.textColor = color;
return this;
}
/**
* 设置进度条之前的颜色
*
*/
public DownloadProgress setPreProgress(int precolor) {
this.preColor = precolor;
return this;
}
/**
* 设置进度颜色
*
* @param color
*/
public DownloadProgress setProgressColor(int color) {
this.progressColor = color;
return this;
}
/**
* 设置圆心中间的背景颜色
*
* @param color
* @return
*/
public DownloadProgress setCircleBackgroud(int color) {
this.CircleColor = color;
return this;
}
/**
* 设置圆相对整个控件的宽度或者高度的占用比例
*
* @param scale
*/
public DownloadProgress setPaddingscale(float scale) {
this.paddingscale = scale;
return this;
}
/**
* 设置开始的位置
*
* @param startAngle
* 0~360
* <p>
* ps 0代表在最右边 90 最下方 按照然后顺时针旋转
*/
public DownloadProgress setStartAngle(int startAngle) {
this.startAngle = startAngle;
return this;
}
public interface onProgressListener {
void onProgress(int value);
}
}

2.在attrs文件添加如下代码

1
2
3
4
<declare-styleable name="DownloadProgress">
<!-- 状态0未下载 1下载中 2下载完成 -->
<attr name="statue" format="integer" />
</declare-styleable>

3.使用方法

在xml布局中:

1
2
3
4
5
6
7
8
<com.tyky.edu.teacher.ui.DownloadProgress
android:id="@+id/download_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="center"
app:statue="1"
android:layout_marginRight="10dp" />

记得在父布局加上xmlns:android="http://schemas.android.com/apk/res/android"

下载回调的时候setStatue()来更改状态,setProgress更改进度值

还有可以优化的地方,加上状态切换的动画,后面有时间再做。

1234
Dino

Dino

Life is made up of small pleasures.

16 日志
5 标签
GitHub Facebook
© 2017 Dino