- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章自定义滑动按钮为例图文剖析Android自定义View绘制由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
自定义view一直是横在android开发者面前的一道坎.
1、view和viewgroup的关系 。
从view和viewgroup的关系来看,viewgroup继承view.
view的子类,多是功能型的控件,提供绘制的样式,比如imageview,textview等,而viewgroup的子类,多用于管理控件的大小,位置,如linearlayout,relativelayout等,从下图可以看出 。
从实际应用中看,他们又是组合关系,我们在布局中,常常是一个viewgroup嵌套多个viewgroup或view,而被嵌套的viewgroup又会嵌套多个viewgroup或view 。
如下 。
2、view的绘制流程 。
从view源码来看,主要关系三个方法:
1、measure():测量 一个final方法,控制控件的大小 2、layout():布局 用来控制自己的布局位置 有相对性,只相对于自己的父类布局,不关心祖宗布局 3、draw():绘制 用来控制控件的显示样式 。
流程: 流程 measure --> layout --> draw 。
对应于我们要实现的方法是 。
onmeasure() 。
onlayout() 。
ondraw() 。
实际绘制中,我们的思考顺序一般是这样的:
是否需要控制控件的大小-->是-->onmeasure() (1)如果这个自定义view不是viewgroup,onmeasure()方法调用setmeasuredeminsion(width,height):用来设置自己的大小 (2)如果是viewgroup,onmeasure()方法调用 ,child.measure()测量孩子的大小,给出孩子的期望大小值,之后-->setmeasuredeminsion(width,height):用来设置自己的大小 。
是否需要控制控件的摆放位置-->是 -->onlayout () 。
是否需要控制控件的样子-->是 -->ondraw ()-->canvas的绘制 。
下面是我绘制的流程图:
下面以自定义滑动按钮为例,说明自定义view的绘制流程 。
我们期待实现这样的效果:
拖动或点击按钮,开关向右滑动,变成 。
其中开关能随着手指的触摸滑动到相应位置,直到最后才固定在开关位置上 。
新建一个类继承自view,实现其两个构造方法 。
1
2
3
4
5
6
7
8
9
10
|
public
class
switchbuttonview
extends
view {
public
switchbuttonview(context context) {
this
(context,
null
);
}
public
switchbuttonview(context context, attributeset attrs) {
super
(context, attrs);
}
|
drawable资源中添加这两张图片 。
借此,我们可以用onmeasure()确定这个控件的大小 。
1
2
3
4
5
6
7
|
@override
protected
void
onmeasure(
int
widthmeasurespec,
int
heightmeasurespec) {
mswitchbutton = bitmapfactory.decoderesource(getresources(), r.drawable.switch_background);
mslidebutton = bitmapfactory.decoderesource(getresources(), r.drawable.slide_button_background);
setmeasureddimension(mswitchbutton.getwidth(), mswitchbutton.getheight());
}
|
这个控件并不需要控制其摆放位置,略过onlayout(); 。
接下来ondraw()确定其形状.
但我们需要根据我们点击控件的不同行为来确定形状,这需要重写ontouchevent() 。
其中的逻辑是:
当按下时,触发事件motionevent.action_down,若此时状态为关:
(1)若手指触摸点(通过event.getx()得到)在按钮的 中线右侧,按钮向右滑动一段距离(event.getx()与开关控件一半宽度之差,具体看下文源码) 。
(2)若手指触摸点在按钮中线左侧,按钮依旧处于最左(即“关”的状态).
若此时状态为开:
(1)若手指触摸点在按钮中线左侧,按钮向左滑动一段距离 。
(2)若手指触摸点在按钮中线右侧,按钮依旧处于最右(即“开”的状态) 。
当滑动时,触发时间motionevent.action_move,逻辑与按下时一致 。
注意,ontouchevent()需要设置返回值 为 return true,否则无法响应滑动事件 。
当手指收起时,若开关中线位于整个控件中线左侧,设置状态为关,反之,设置为开.
具体源码如下所示:(还对外提供了一个暴露此时开关状态的接口) 。
自定义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
|
package
com.lian.switchtogglebutton;
import
android.content.context;
import
android.graphics.bitmap;
import
android.graphics.bitmapfactory;
import
android.graphics.canvas;
import
android.graphics.paint;
import
android.util.attributeset;
import
android.util.log;
import
android.view.motionevent;
import
android.view.view;
/**
* created by lian on 2016/3/20.
*/
public
class
switchbuttonview
extends
view {
private
static
final
int
state_null =
0
;
//默认状态
private
static
final
int
state_down =
1
;
private
static
final
int
state_move =
2
;
private
static
final
int
state_up =
3
;
private
bitmap mslidebutton;
private
bitmap mswitchbutton;
private
paint mpaint =
new
paint();
private
int
buttonstate = state_null;
private
float
mdistance;
private
boolean
isopened =
false
;
private
onswitchlistener mlistener;
public
switchbuttonview(context context) {
this
(context,
null
);
}
public
switchbuttonview(context context, attributeset attrs) {
super
(context, attrs);
}
@override
protected
void
onmeasure(
int
widthmeasurespec,
int
heightmeasurespec) {
mswitchbutton = bitmapfactory.decoderesource(getresources(), r.drawable.switch_background);
mslidebutton = bitmapfactory.decoderesource(getresources(), r.drawable.slide_button_background);
setmeasureddimension(mswitchbutton.getwidth(), mswitchbutton.getheight());
}
@override
protected
void
ondraw(canvas canvas) {
super
.ondraw(canvas);
if
(mswitchbutton!=
null
){
canvas.drawbitmap(mswitchbutton,
0
,
0
, mpaint);
}
//buttonstate的值在ontouchevent()中确定
switch
(buttonstate){
case
state_down:
case
state_move:
if
(!isopened){
float
middle = mslidebutton.getwidth() / 2f;
if
(mdistance > middle) {
float
max = mswitchbutton.getwidth() - mslidebutton.getwidth();
float
left = mdistance - middle;
if
(left >= max) {
left = max;
}
canvas.drawbitmap(mslidebutton,left,
0
,mpaint);
}
else
{
canvas.drawbitmap(mslidebutton,
0
,
0
,mpaint);
}
}
else
{
float
middle = mswitchbutton.getwidth() - mslidebutton.getwidth() / 2f;
if
(mdistance < middle){
float
left = mdistance-mslidebutton.getwidth()/2f;
float
min =
0
;
if
(left <
0
){
left = min;
}
canvas.drawbitmap(mslidebutton,left,
0
,mpaint);
}
else
{
canvas.drawbitmap(mslidebutton,mswitchbutton.getwidth()-mslidebutton.getwidth(),
0
,mpaint);
}
}
break
;
case
state_null:
case
state_up:
if
(isopened){
log.d(
"开关"
,
"开着的"
);
canvas.drawbitmap(mslidebutton,mswitchbutton.getwidth()-mslidebutton.getwidth(),
0
,mpaint);
}
else
{
log.d(
"开关"
,
"关着的"
);
canvas.drawbitmap(mslidebutton,
0
,
0
,mpaint);
}
break
;
default
:
break
;
}
}
@override
public
boolean
ontouchevent(motionevent event) {
switch
(event.getaction()){
case
motionevent.action_down:
mdistance = event.getx();
log.d(
"down"
,
"按下"
);
buttonstate = state_down;
invalidate();
break
;
case
motionevent.action_move:
buttonstate = state_move;
mdistance = event.getx();
log.d(
"move"
,
"移动"
);
invalidate();
break
;
case
motionevent.action_up:
mdistance = event.getx();
buttonstate = state_up;
log.d(
"up"
,
"起开"
);
if
(mdistance >= mswitchbutton.getwidth() / 2f){
isopened =
true
;
}
else
{
isopened =
false
;
}
if
(mlistener !=
null
){
mlistener.onswitchchanged(isopened);
}
invalidate();
break
;
default
:
break
;
}
return
true
;
}
public
void
setonswitchlistener(onswitchlistener listener){
this
.mlistener = listener;
}
public
interface
onswitchlistener{
void
onswitchchanged(
boolean
isopened);
}
}
|
demoactivity:
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
|
package
com.lian.switchtogglebutton;
import
android.os.bundle;
import
android.support.v7.app.appcompatactivity;
import
android.widget.toast;
public
class
mainactivity
extends
appcompatactivity {
@override
protected
void
oncreate(bundle savedinstancestate) {
super
.oncreate(savedinstancestate);
setcontentview(r.layout.activity_main);
switchbuttonview switchbuttonview = (switchbuttonview) findviewbyid(r.id.switchbutton);
switchbuttonview.setonswitchlistener(
new
switchbuttonview.onswitchlistener() {
@override
public
void
onswitchchanged(
boolean
isopened) {
if
(isopened) {
toast.maketext(mainactivity.
this
,
"打开"
, toast.length_short).show();
}
else
{
toast.maketext(mainactivity.
this
,
"关闭"
, toast.length_short).show();
}
}
});
}
}
|
布局:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?xml version=
"1.0"
encoding=
"utf-8"
?>
<relativelayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:paddingbottom=
"@dimen/activity_vertical_margin"
android:paddingleft=
"@dimen/activity_horizontal_margin"
android:paddingright=
"@dimen/activity_horizontal_margin"
android:paddingtop=
"@dimen/activity_vertical_margin"
tools:context=
"com.lian.switchtogglebutton.mainactivity"
>
<com.lian.switchtogglebutton.switchbuttonview
android:id=
"@+id/switchbutton"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
/>
</relativelayout>
|
以上就是本文的全部内容,希望对大家的学习有所帮助.
最后此篇关于自定义滑动按钮为例图文剖析Android自定义View绘制的文章就讲到这里了,如果你想了解更多关于自定义滑动按钮为例图文剖析Android自定义View绘制的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我最近购买了《C 编程语言》并尝试了 Ex 1-8这是代码 #include #include #include /* * */ int main() { int nl,nt,nb;
早上好!我有一个变量“var”,可能为 0。我检查该变量是否为空,如果不是,我将该变量保存在 php session 中,然后调用另一个页面。在这个新页面中,我检查我创建的 session 是否为空,
我正在努力完成 Learn Python the Hard Way ex.25,但我无法理解某些事情。这是脚本: def break_words(stuff): """this functio
我是一名优秀的程序员,十分优秀!