首先,我们得先要明白ViewGroup是什么,职责是什么?
ViewGroup就是用来放置View控件的的容器,职责是测量每一个子view的大小,还有摆放的位置。
* 1,写一个类继承于ViewGroup
* 2,重载onMeasure方法,用于测量的子View的大小
* 3,重载onLayout,用于安置子view的位置
到这里,一个ViewGroup就算自定义完成了,
下面的步骤是实现ViewGroup的功能
想要实现子类滑动的效果,就要借助Scroller这个类,这个类的使用请参考http://blog.csdn.net/qq_15949077/article/details/46940507
* 4.然后通过Gesturector手势识别器的ontuchEvent屏幕监听器即可实现页面的滑动
* 5,最后写一个内部接口,对外提供一个监听的set方法
看代码吧,这是一个实现类似viewPager的例子,里面的Scroller类作用很大
public class MyViewGroup extends ViewGroup {
GestureDetector gd;//手势识别器
Scroller scroll;
int itemID=0;
int firstX;
int lastX;
int dis;
boolean isFling;
itemChangelistener listener;
/**
* 事件中断器用的变量
*/
int downx;
int downy;
int movex;
int movey;
int distancex;
int distancey;
public MyViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
scroll=new Scroller(context);
gd=new GestureDetector(context, new OnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
// TODO Auto-generated method stub
if(itemID==0&&distanceX<0){
}
else if(itemID==getChildCount()-1&&distanceX>0){
}
else{
scrollBy((int) distanceX, 0);
}
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
isFling=true;
if(itemID==0&&velocityX>0){
}
else if(itemID==getChildCount()-1&&velocityX<0){
}
else if(velocityX>0){
itemID--;
}
else if(velocityX<0){
itemID++;
}
return false;
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
});
}
//测量子view的大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
for(int i=0;i<this.getChildCount();i++){
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
}
}
//指定子View的位置
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
for(int i=0;i<this.getChildCount();i++){
getChildAt(i).layout(i*getWidth(), 0, i*getWidth()+getWidth(), getHeight());
}
}
/**
* 事件中断器
* 比较上下和左右移动的距离谁大,大的就移动谁
*
*
* 如果返回值为true:则代表事件到这来被中断掉,就会执行自己的onTouchEvent,
* 注意,奇怪的是从move开始,而不是down,所以在down里有做处理的要注意,
* 而且这里有时会产生跳动bug,原因不知道,理解不了,(不是因为从move开始执行的原因,因为在down都没做处理的情况下也一样跳动)
* 解决这个bug的方法也很简单,在dowm的方法里将这个事件传给手势识别器就ok了
*
* 如果返回值为false:将不会执行onTouchEvent方法,而是把事件传给子控件
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
boolean result=false;
switch(ev.getAction()){
case MotionEvent.ACTION_DOWN:
gd.onTouchEvent(ev);
downx=(int) ev.getX();
downy=(int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
movex=(int) ev.getX();
movey=(int) ev.getY();
distancex=Math.abs(movex-downx);
distancey=Math.abs(movey-downy);
if(distancex>distancey&&distancex>10){
result= true;
}
else{
result= false;
}
// else if(distancex<distancey&&distancey>10){
// result= false;
// }
break;
}
return result;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
gd.onTouchEvent(event);
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
firstX=(int)event.getX();
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
lastX=(int) event.getX();
dis=lastX-firstX;
if(!isFling){
if(itemID==0&&dis>0){
}
else if(itemID==getChildCount()-1&&dis<0){
}
else if(dis>0&&dis>getWidth()/5){
itemID--;
}
else if(dis<0&&Math.abs(dis)>getWidth()/5){
itemID++;
}
}
myScrollto(itemID);
break;
}
return true;
}
/**
* 开始移动
* @param ItemID
*/
public void myScrollto(int itemID){
if(listener!=null){
listener.itemID(itemID);
}
int dis=itemID*getWidth()-getScrollX();
scroll.startScroll(getScrollX(), 0, dis, 0, Math.abs(dis));
invalidate();
}
/**
* 执行invalidata方法后回调
*/
@Override
public void computeScroll() {
// TODO Auto-generated method stub
super.computeScroll();
if(scroll.computeScrollOffset()){
scrollTo(scroll.getCurrX(), 0);
invalidate();
}
else{
isFling=false;
}
}
/**
* 对外部提供的设置指定页面的方法
* @param itemID
*/
public void setItemID(int itemID){
this.itemID=itemID;
myScrollto(itemID);
}
/**
* 对外提供一个监听页面改变后获取id的方法
* @param listener
*/
public void setonItemChangelistener(itemChangelistener listener){
this.listener=listener;
}
/**
* 对外提供的滑动到哪个页面id的接口
* @author Administrator
*
*/
interface itemChangelistener{
void itemID(int ItemID);
}
}