头像滑动,中间放大并带点击选中效果

在之前的项目中,要做店员快速登录的一个界面,入下图所示: 

上面这个需求,首先想到的就是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在屏幕中的坐标区域进行了监听事件。

到此这个需求就完成了,撸代码还是得多点变通之道,有些时候,一些淫荡的方式实现的效果,还是很令人惊喜的。




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值