在之前的项目中,要做店员快速登录的一个界面,入下图所示:
上面这个需求,首先想到的就是viewpager来实现这个效果。
首先,就是让viewpa能显示多个图片,这个在网上搜一下,有很多的讲这个的,要让viewpager显示多张图,只要在xml布局里面将viewpager父控件的clipChildren的属性设置为false就行了,还有就是要将viewpager的父view 的touch事件下发,不然只有中间的图片能拖动,代码如下:
accountParentView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return accoViewPager.dispatchTouchEvent(motionEvent);
}
});
这样就实现了第一步,已经可以展示多个图片,也可以左右拖动了。
第二步,就是来实现当头像拖动到中央区域的时候慢慢放大,拖出中央区域的时候,在慢慢变回正常的效果,这个就要去实现ViewPager的PagerTransFormer的接口,这个在网上一搜,也有很多教程,主要代码如下:
class AccountPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 1.0f; //正常大小
private static final float MAX_SCALE = 1.2f; //放大到1.2倍
@Override
public void transformPage(View page, float position) {
if (position < -1) {
position = -1;
} else if (position > 1) {
position = 1;
}
float tempScale = position < 0 ? 1 + position : 1 - position;
float slope = (MAX_SCALE - MIN_SCALE) / 1;
float scaleValue = MIN_SCALE + tempScale * slope; //在滑动过程中,计算放大和缩小的值
page.setScaleX(scaleValue); //
page.setScaleY(scaleValue); //设置动画缩放的值
ImageView imageView = (ImageView) page.findViewById(R.id.iv_head);
if (position == 0) {
imageView.setBackgroundResource(R.drawable.shape_white_circle);
} else {
imageView.setBackgroundResource(R.drawable.shape_circle_head_bg);
}
}
}
上面的的代码,给viewpager添加了一个滑动时候的切换的动画效果,关键就是上面的position 的值来确定当前显示的图片的位置,具体原理可以看网上和google官方的文档,
这个写好,只需要set一下就行了:
accoViewPager.setPageTransformer(true, new AccountPageTransformer());
还有最后一个需求,点击其它头像的时候,点击的头像要自动滑动到中间来,想想这个挺简单,给viewPager里面的view设置个点击事件不就行了,结果too young too simple~
点击事件完全是混乱的,上面的头像乱跳,点第一个头像,结果第二个跑到中间去了,点第二个,第四个头像又跑到中间去,,无语啊,然后又去网上找答案,果然有很多人跟我一样,造成这种点击混乱的原因好像很复杂(我已经忘了~ =_=)试了好多网上的方法,都没用,最后楼主啊想到了一个淫荡的办法,通过手指触摸的坐标,来判断点击在哪个头像上,然后将该头像移动到中间。
因为上面最多显示5个头像(显示多少都是只定的),开始先定义好5个头像位置对应的坐标矩阵:
private Rect rect0, rect1, rect2, rect3, rect4; //5个头像对应的坐标的矩阵
接下来就要计算出这5个头像的坐标区域,代码如下:
accoViewPager.addOnLayoutChangeListener(new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
Rect rect = new Rect();
v.getGlobalVisibleRect(rect);
initHeadRect(rect, v.getWidth());
}
}); //这个监听放在view初始化的地方,用来获取viewPager这个控件的坐标区域在这里实际上获取了中心头像的坐标区域,viewPgar 的实际大小就只有中间这一块
//初始化5个头像的坐标矩阵(根据中心头像的坐标区域,计算出其他4个)
private void initHeadRect(Rect rect, int w) {
rect2 = new Rect(rect);
int margin = 30; //这个是两个头像之间的间距
int top = rect2.top;
int bottom = rect2.bottom;
int right1 = rect2.left - margin;
rect1 = new Rect(right1 - w, top, right1, bottom);
int right0 = rect1.left - margin;
rect0 = new Rect(right0 - w, top, right0, bottom);
int left3 = rect2.right + margin;
rect3 = new Rect(left3, top, left3 + w, bottom);
int left4 = rect3.right + margin;
rect4 = new Rect(left4, top, left4 + w, bottom);
}
上面这段代码的作用,注释已经写的很清楚了,不在多解释。
接下是最后一步,用touch事件来做点击事件,代码如下:
private float orgX = 0f;
accoViewPager.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
orgX = event.getRawX();
break;
case MotionEvent.ACTION_UP:
int x = (int) event.getRawX();
int y = (int) event.getRawY();
Log.d("orgX", orgX + "," + x);
if (Math.abs(x - orgX) < 100) { ---------//只要横向滑动距离小于100,就当做点击事件处理
int p = getClickPosition(x, y); ---------//获取手指拿起来时,坐标停留在哪个头像区域
if (p != -100) {
int newPosition = selectPostion + p; --//拿到viewpager中view 的实际position
if (newPosition >= 0 && newPosition <= clerkList.size()) {
accoViewPager.setCurrentItem(newPosition); --//将点击的view滚动到中间
return true;
}
}
}
break;
}
return false;
}
});
//获取点击的坐标区域(判断点击坐标在哪个头像坐标区域内)
private int getClickPosition(int x, int y) {
int p = -100;
if (rect0.contains(x, y)) {
p = -2;
} else if (rect1.contains(x, y)) {
p = -1;
} else if (rect2.contains(x, y)) {
p = 0;
} else if (rect3.contains(x, y)) {
p = 1;
} else if (rect4.contains(x, y)) {
p = 2;
}
return p;
}
代码中注释都写了,实际上我这种方式只是绕过了对viewpager中view的直接点击和触摸的处理,仅仅是对该view在屏幕中的坐标区域进行了监听事件。
到此这个需求就完成了,撸代码还是得多点变通之道,有些时候,一些淫荡的方式实现的效果,还是很令人惊喜的。