Android自定义组件系列【3】自定义ViewGroup实现侧滑
来源:互联网 发布:大话西游2账号数据库 编辑:程序博客网 时间:2024/04/27 09:02
有关自定义ViewGroup的文章已经很多了,我为什么写这篇文章,对于初学者或者对自定义组件比较生疏的朋友虽然可以拿来主义的用了,但是要一步一步的实现和了解其中的过程和原理才能真真脱离别人的代码,举一反三却不容易,很多博主其实不愿意一步一步的去写,这样很耗时,但是如果能对读者有帮助,能从这篇文章中学会自定义组件就达到我的目的了。
第一步:搭建框架来实现一个3/5和2/5分屏的界面,效果如下:
最外层是一个自定义的ViewGroup布局文件如下:
01.
<strong>
package
com.example.testscrollto;
02.
03.
import
android.content.Context;
04.
import
android.util.AttributeSet;
05.
import
android.view.View;
06.
import
android.view.ViewGroup;
07.
import
android.view.View.MeasureSpec;
08.
09.
public
class
MyScrollView
extends
ViewGroup{
10.
11.
private
int
mWidth;
12.
private
int
mHeight;
13.
14.
private
float
mMenuWeight =
3
.0f /
5
;
//菜单界面比例
15.
16.
private
View mMenuView;
//菜单界面
17.
private
View mPriView;
//内容界面
18.
19.
public
MyScrollView(Context context, AttributeSet attrs) {
20.
super
(context, attrs);
21.
22.
}
23.
24.
@Override
25.
protected
void
onLayout(
boolean
arg0,
int
arg1,
int
arg2,
int
arg3,
int
arg4) {
26.
System.out.println(
"执行了onLayout"
);
27.
mMenuView.layout(
0
,
0
, (
int
)(mWidth * mMenuWeight), mHeight);
28.
mPriView.layout((
int
)(mWidth * mMenuWeight),
0
, mWidth, mHeight);
29.
}
30.
31.
@Override
32.
protected
void
onMeasure(
int
widthMeasureSpec,
int
heightMeasureSpec) {
33.
System.out.println(
"执行了onMeasure"
);
34.
super
.onMeasure(widthMeasureSpec, heightMeasureSpec);
35.
/*
36.
* onMeasure传入的两个参数是由上一层控件传入的大小,有多种情况,重写该方法时需要对计算控件的实际大小,
37.
* 然后调用setMeasuredDimension(int, int)设置实际大小。
38.
* onMeasure传入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸数值,而是将模式和尺寸组合在一起的数值。
39.
* 我们需要通过int mode = MeasureSpec.getMode(widthMeasureSpec)得到模式,
40.
* 用int size = MeasureSpec.getSize(widthMeasureSpec)得到尺寸。
41.
* mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。
42.
* MeasureSpec.EXACTLY是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。
43.
* MeasureSpec.AT_MOST是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
44.
* MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。
45.
*/
46.
mWidth = MeasureSpec.getSize(widthMeasureSpec);
//获取MyScrollView的宽度
47.
mHeight = MeasureSpec.getSize(heightMeasureSpec);
//获取MyScrollView的高度
48.
}
49.
50.
/**设置右滑的菜单View*/
51.
public
void
setMenu(View menu){
52.
mMenuView = menu;
53.
addView(mMenuView);
54.
}
55.
56.
/**
57.
* 设置主界面View
58.
*/
59.
public
void
setPrimary(View primary){
60.
mPriView = primary;
61.
addView(mPriView);
62.
}
63.
64.
}
65.
</strong>
1.
<strong>
@Override
2.
protected
void
onLayout(
boolean
arg0,
int
arg1,
int
arg2,
int
arg3,
int
arg4) {
3.
mMenuView.layout(-(
int
)(mWidth * mMenuWeight),
0
,
0
, mHeight);
4.
mPriView.layout(
0
,
0
, mWidth, mHeight);
5.
}</strong>
第三步:实现左右滑动
001.
<strong>
package
com.example.testscrollto;
002.
003.
import
android.content.Context;
004.
import
android.util.AttributeSet;
005.
import
android.view.MotionEvent;
006.
import
android.view.View;
007.
import
android.view.ViewGroup;
008.
import
android.widget.Scroller;
009.
010.
public
class
MyScrollView
extends
ViewGroup{
011.
012.
private
Context mContext;
013.
private
int
mWidth;
014.
private
int
mHeight;
015.
016.
private
float
mMenuWeight =
3
.0f /
5
;
//菜单界面比例
017.
018.
private
View mMenuView;
//菜单界面
019.
private
View mPriView;
//内容界面
020.
021.
private
boolean
mIsShowMenu;
022.
023.
private
Scroller mScroller;
024.
025.
026.
public
MyScrollView(Context context, AttributeSet attrs) {
027.
super
(context, attrs);
028.
mContext = context;
029.
mScroller =
new
Scroller(mContext);
030.
}
031.
032.
@Override
033.
protected
void
onLayout(
boolean
arg0,
int
arg1,
int
arg2,
int
arg3,
int
arg4) {
034.
mMenuView.layout(-(
int
)(mWidth * mMenuWeight),
0
,
0
, mHeight);
035.
mPriView.layout(
0
,
0
, mWidth, mHeight);
036.
}
037.
038.
@Override
039.
protected
void
onMeasure(
int
widthMeasureSpec,
int
heightMeasureSpec) {
040.
super
.onMeasure(widthMeasureSpec, heightMeasureSpec);
041.
mWidth = MeasureSpec.getSize(widthMeasureSpec);
//获取MyScrollView的宽度
042.
mHeight = MeasureSpec.getSize(heightMeasureSpec);
//获取MyScrollView的高度
043.
}
044.
045.
/**设置右滑的菜单View*/
046.
public
void
setMenu(View menu){
047.
mMenuView = menu;
048.
addView(mMenuView);
049.
}
050.
051.
/**
052.
* 设置主界面View
053.
*/
054.
public
void
setPrimary(View primary){
055.
mPriView = primary;
056.
addView(mPriView);
057.
}
058.
059.
private
float
mDownX;
060.
061.
@Override
062.
public
boolean
onTouchEvent(MotionEvent event) {
063.
float
x = event.getX();
064.
switch
(event.getAction()) {
065.
case
MotionEvent.ACTION_DOWN:
066.
System.out.println(
"ACTION_DOWN"
);
067.
mDownX = x;
//记录按下时的x坐标
068.
break
;
069.
case
MotionEvent.ACTION_UP:
070.
System.out.println(
"ACTION_UP"
);
071.
int
dis = (
int
) (x - mDownX);
//滑动的距离
072.
if
(Math.abs(dis) > (mWidth * mMenuWeight /
2
)){
073.
if
(dis >
0
){
//如果>0则是向右滑动
074.
showMenu();
075.
}
else
{
//如果<0则是向左滑动
076.
hideMenu();
077.
}
078.
}
079.
break
;
080.
default
:
081.
break
;
082.
}
083.
084.
return
true
;
085.
}
086.
087.
@Override
088.
public
void
computeScroll() {
089.
super
.computeScroll();
090.
if
(mScroller.computeScrollOffset()){
091.
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
092.
postInvalidate();
093.
}
094.
}
095.
096.
public
boolean
isShowMenu(){
097.
return
mIsShowMenu;
098.
}
099.
100.
public
void
showMenu(){
101.
if
(mIsShowMenu){
102.
return
;
103.
}
104.
mIsShowMenu =
true
;
//标记菜单已经显示
105.
int
dx = (
int
)(mWidth * mMenuWeight);
//滑动到目标位置的距离
106.
mScroller.startScroll(getScrollX(),
0
, -dx,
0
,
500
);
107.
invalidate();
108.
}
109.
110.
public
void
hideMenu(){
111.
if
(!mIsShowMenu){
112.
return
;
113.
}
114.
mIsShowMenu =
false
;
115.
int
dx = (
int
)(mWidth * mMenuWeight);
116.
mScroller.startScroll(getScrollX(),
0
, dx,
0
,
500
);
117.
invalidate();
118.
}
119.
120.
121.
}
122.
</strong>
1.
<strong>mScroller.startScroll(getScrollX(),
0
, -dx,
0
,
500
);
2.
invalidate();</strong>
1.
<strong>
public
interface
OnMenuChangedListener{
2.
public
void
onChanged(
boolean
isShow);
3.
}
4.
5.
public
void
setOnMenuChangedListener(OnMenuChangedListener listener){
6.
mListener = listener;
7.
}</strong>
01.
<strong>
public
void
showMenu(){
02.
if
(mIsShowMenu){
03.
return
;
04.
}
05.
mIsShowMenu =
true
;
06.
int
dx = (
int
)(mWidth * mMenuWeight);
07.
mScroller.startScroll(getScrollX(),
0
, -dx,
0
,
500
);
08.
if
(mListener !=
null
){
09.
mListener.onChanged(mIsShowMenu);
10.
}
11.
invalidate();
12.
}
13.
14.
public
void
hideMenu(){
15.
if
(!mIsShowMenu){
16.
return
;
17.
}
18.
mIsShowMenu =
false
;
19.
int
dx = (
int
)(mWidth * mMenuWeight);
20.
mScroller.startScroll(getScrollX(),
0
, dx,
0
,
500
);
21.
if
(mListener !=
null
){
22.
mListener.onChanged(mIsShowMenu);
23.
}
24.
invalidate();
25.
}</strong>
1.
<strong> mScrollView.setOnMenuChangedListener(
new
OnMenuChangedListener() {
2.
3.
@Override
4.
public
void
onChanged(
boolean
isShow) {
5.
System.out.println(
"窗口切换了一次"
);
6.
}
7.
});</strong>
MainActivity.java
01.
<strong>
package
com.example.testrefreshview;
02.
03.
04.
import
android.app.Activity;
05.
import
android.graphics.Color;
06.
import
android.os.Bundle;
07.
import
android.view.View;
08.
import
android.view.View.OnClickListener;
09.
import
android.widget.AdapterView;
10.
import
android.widget.AdapterView.OnItemClickListener;
11.
import
android.widget.ArrayAdapter;
12.
import
android.widget.Button;
13.
import
android.widget.ListView;
14.
15.
import
com.example.testrefreshview.RightScrollView.OnMenuChangedListener;
16.
17.
/**
18.
* 测试具有右滑菜单功能的ViewGroup,RigthScrollView
19.
*@author Lqh
20.
*/
21.
public
class
MainActivity
extends
Activity {
22.
23.
private
RightScrollView mRightScrollView;
24.
private
Button mShowMenuBtn;
25.
private
ListView mMenuList;
26.
private
ArrayAdapter<String> mAdapter;
27.
private
String[] menus = {
"附近的人"
,
"我的资料"
,
"设置"
,
"游戏"
,
"即时聊天"
};
28.
29.
@Override
30.
protected
void
onCreate(Bundle savedInstanceState) {
31.
super
.onCreate(savedInstanceState);
32.
setContentView(R.layout.rightscrollview_test);
33.
mRightScrollView = (RightScrollView)findViewById(R.id.rightscrollview);
34.
final
View menu = getLayoutInflater().inflate(R.layout.rightscrollview_menu,
null
);
35.
final
View primary = getLayoutInflater().inflate(R.layout.rightscrollview_primary,
null
);
36.
mMenuList = (ListView) menu.findViewById(R.id.list_right_menu);
37.
mShowMenuBtn = (Button) primary.findViewById(R.id.btn_showmenu);
38.
mAdapter =
new
ArrayAdapter<String>(
this
, android.R.layout.simple_list_item_1, menus);
39.
mMenuList.setAdapter(mAdapter);
40.
41.
mShowMenuBtn.setOnClickListener(
new
OnClickListener() {
42.
public
void
onClick(View v) {
43.
if
(mRightScrollView.isShowMenu()){
44.
mRightScrollView.hideMenu();
45.
}
else
{
46.
mRightScrollView.showMenu();
47.
}
48.
}
49.
});
50.
51.
mRightScrollView.setOnMenuChangedListener(
new
OnMenuChangedListener() {
52.
public
void
onChanged(
boolean
isShow) {
53.
if
(isShow){
54.
mShowMenuBtn.setText(
"隐藏菜单"
);
55.
}
else
{
56.
mShowMenuBtn.setText(
"显示菜单"
);
57.
}
58.
}
59.
});
60.
61.
mRightScrollView.setMenu(menu);
62.
mRightScrollView.setPrimary(primary);
63.
64.
mMenuList.setOnItemClickListener(
new
OnItemClickListener() {
65.
public
void
onItemClick(AdapterView<?> parent, View view,
int
position,
long
id) {
66.
switch
(position){
67.
case
0
:
68.
primary.setBackgroundColor(Color.CYAN);
69.
break
;
70.
case
1
:
71.
primary.setBackgroundColor(Color.BLUE);
72.
break
;
73.
case
2
:
74.
primary.setBackgroundColor(Color.GRAY);
75.
break
;
76.
case
3
:
77.
primary.setBackgroundColor(Color.MAGENTA);
78.
break
;
79.
case
4
:
80.
primary.setBackgroundColor(Color.YELLOW);
81.
break
;
82.
}
83.
mRightScrollView.hideMenu();
84.
}
85.
});
86.
87.
}
88.
}</strong>
001.
<strong>
package
com.example.testrefreshview;
002.
003.
import
android.content.Context;
004.
import
android.util.AttributeSet;
005.
import
android.view.MotionEvent;
006.
import
android.view.View;
007.
import
android.view.ViewGroup;
008.
import
android.widget.Scroller;
009.
010.
/**
011.
* 具有右滑菜单的ViewGroup,类似于Facebook的主界面
012.
* @author Lqh
013.
*/
014.
public
class
RightScrollView
extends
ViewGroup {
015.
016.
private
Context mContext;
017.
private
Scroller mScroller;
018.
private
View mMenuView;
019.
private
View mPriView;
020.
private
int
mWidth;
021.
private
int
mHeight;
022.
private
boolean
mIsShowMenu;
023.
private
float
mMenuWeight =
3
.0f /
5
;
024.
private
OnMenuChangedListener mListener;
025.
026.
027.
public
RightScrollView(Context context) {
028.
this
(context,
null
);
029.
}
030.
031.
public
RightScrollView(Context context, AttributeSet attrs) {
032.
super
(context, attrs);
033.
034.
mContext = context;
035.
mScroller =
new
Scroller(mContext);
036.
037.
}
038.
039.
/**设置右滑的菜单View*/
040.
public
void
setMenu(View menu){
041.
mMenuView = menu;
042.
addView(mMenuView);
043.
}
044.
045.
/**
046.
* 设置主界面View
047.
*/
048.
public
void
setPrimary(View primary){
049.
mPriView = primary;
050.
addView(mPriView);
051.
}
052.
053.
public
boolean
isShowMenu(){
054.
return
mIsShowMenu;
055.
}
056.
057.
public
void
setOnMenuChangedListener(OnMenuChangedListener listener){
058.
mListener = listener;
059.
}
060.
061.
062.
public
void
showMenu(){
063.
if
(mIsShowMenu){
064.
return
;
065.
}
066.
mIsShowMenu =
true
;
067.
int
dx = (
int
)(mWidth * mMenuWeight);
068.
mScroller.startScroll(getScrollX(),
0
, -dx,
0
,
500
);
069.
if
(mListener !=
null
){
070.
mListener.onChanged(mIsShowMenu);
071.
}
072.
invalidate();
073.
}
074.
075.
public
void
hideMenu(){
076.
if
(!mIsShowMenu){
077.
return
;
078.
}
079.
mIsShowMenu =
false
;
080.
int
dx = (
int
)(mWidth * mMenuWeight);
081.
mScroller.startScroll(getScrollX(),
0
, dx,
0
,
500
);
082.
if
(mListener !=
null
){
083.
mListener.onChanged(mIsShowMenu);
084.
}
085.
invalidate();
086.
}
087.
088.
private
float
mDownX;
089.
090.
@Override
091.
public
boolean
onTouchEvent(MotionEvent event) {
092.
093.
float
x = event.getX();
094.
095.
switch
(event.getAction()){
096.
case
MotionEvent.ACTION_DOWN:
097.
mDownX = x;
098.
break
;
099.
case
MotionEvent.ACTION_UP:
100.
int
dis = (
int
) (x - mDownX);
101.
if
(Math.abs(dis) > (mWidth * mMenuWeight /
2
)){
102.
if
(dis >
0
){
103.
showMenu();
104.
}
else
{
105.
hideMenu();
106.
}
107.
}
108.
break
;
109.
}
110.
111.
return
true
;
112.
}
113.
114.
115.
@Override
116.
public
void
computeScroll() {
117.
super
.computeScroll();
118.
if
(mScroller.computeScrollOffset()){
119.
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
120.
postInvalidate();
121.
}
122.
}
123.
124.
125.
@Override
126.
protected
void
onMeasure(
int
widthMeasureSpec,
int
heightMeasureSpec) {
127.
128.
mWidth = MeasureSpec.getSize(widthMeasureSpec);
129.
mHeight = MeasureSpec.getSize(heightMeasureSpec);
130.
131.
setMeasuredDimension(mWidth, mHeight);
132.
int
widthSpec = MeasureSpec.makeMeasureSpec((
int
)(mWidth * mMenuWeight), MeasureSpec.EXACTLY);
133.
int
heightSpec = MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY);
134.
mMenuView.measure(widthSpec, heightSpec);
135.
136.
widthSpec = MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY);
137.
mPriView.measure(widthSpec, heightSpec);
138.
}
139.
140.
@Override
141.
protected
void
onLayout(
boolean
changed,
int
l,
int
t,
int
r,
int
b) {
142.
143.
mMenuView.layout(-(
int
)(mWidth * mMenuWeight),
0
,
0
, mHeight);
144.
mPriView.layout(
0
,
0
, mWidth, mHeight);
145.
}
146.
147.
public
interface
OnMenuChangedListener{
148.
public
void
onChanged(
boolean
isShow);
149.
}
150.
151.
152.
}
153.
</strong>
0 0
- Android自定义组件系列【3】自定义ViewGroup实现侧滑
- Android自定义组件系列【3】——自定义ViewGroup实现侧滑
- Android自定义组件系列【3】——自定义ViewGroup实现侧滑
- Android自定义组件系列【4】——自定义ViewGroup实现双侧滑动
- Android自定义组件系列【4】——自定义ViewGroup实现双侧滑动
- viewgroup自定义组件 --- 侧滑组件
- Android 自定义侧滑ViewGroup
- Android自定义组件系列【1】——自定义View及ViewGroup
- Android自定义组件系列【1】——自定义View及ViewGroup
- Android自定义组件系列【1】——自定义View及ViewGroup
- Android 自定义ViewGroup实现GridLayout
- Android 自定义ViewGroup 实现FlowLayout
- Android 自定义ViewGroup 实现FlowLayout
- Android,自定义ViewGroup实现titleBar
- Android自定义viewgroup实现自定义布局
- Android自定义组件之自动换行ViewGroup
- 自定义ViewGroup实现侧滑删除菜单
- android自定义ViewGroup(侧滑菜单)
- 学习笔记之Servlet Filter
- Linux命令----eval命令详解
- java位运算
- jdbc
- UML视图(七)协作图
- Android自定义组件系列【3】自定义ViewGroup实现侧滑
- C++中extern “C”含义深层探索
- 利用Eclipse和Sourcery G++ Lite通过GDBserver在Windows下单步调试嵌入式Linux应用程序
- VMware 中软盘镜像文件 *.flp 使用方法
- 惠普(HP) LaserJet Pro M1136 MFP 黑白多功能激光一体机 (打印 复印 扫描)驱动安装记录
- 最简单的mpi安装
- 《犀利仁师》将播 张哲瀚挑战高丽“求学少年”09:54
- Java界面编程
- 撒法师大哥个的飒飒的个个都是