一个简单的图片滑动展示控件

      首先声明本人Android新人一枚,这是本人第一篇博客,用于对自己知识的巩固,同时把自己写的东西分享出来,希望能帮到有需要的人。

      今天朋友需要一个图片滑动展示的控件,要求图片折叠时除第一张图片,其他都只保留底部一部分可见,可上下滑动展示。

      先讲讲我的思路,本来想用RecyclerView配合隐藏图片来完成的,可是后来一想这样适配性太差,只能用于已知图片数量的情况,于是我决定写一个自定义控件来完成这个需求。这个控件里面最重要的就是控件的大小,绘制图片,控件中图片滑动响应,处理父控件滑动事件的屏蔽。

      首先控大小,我们通过重写onMeasure方法来完成,

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    if (infoList.size() == 0) {
        setMeasuredDimension(pWidth, bHeight);//设置控件宽高
    } else {
        setMeasuredDimension(pWidth, bHeight + infoList.get(infoList.size() - 1).hightTop);//设置控件宽高
    }

}

宽度直接是使用的屏幕宽度,高度我设置了一个默认图片,以这个默认图片的高度bHeight来计算,每多一张图片高度就增加bHeight/4,由于需要对滑动后的控件大小进行改变,我这边用的最后一张图片顶部高度来计算控件高度,效果是一致的。


这是我对滑动后控件大小进行改变的操作。

完成控件大小的设置,就要来绘制图片了,这个我们在onDraw中进行处理,

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Rect srcRect = new Rect(0, 0, pWidth, bHeight);//要绘制的bitmap 区域
    if (list.size() == 0) {
        Rect destRect = new Rect(0, 0, pWidth, bHeight);//要将bitmap 绘制在屏幕的什么地方
        canvas.drawBitmap(bitmap, srcRect, destRect, paint);
    } else {
        for (int i = list.size() - 1; i >= 0; i--) {
            BitmapInfo bitmapInfo = infoList.get(i);
            Rect destRect = new Rect(bitmapInfo.widthLeft, bitmapInfo.hightTop, bitmapInfo.widthRight, bitmapInfo.hightTop + bHeight);//要将bitmap 绘制在屏幕的什么地方
            canvas.drawBitmap(list.get(i), srcRect, destRect, paint);
        }
    }
}

接下来就要处理控件中图片滑动的响应了,首先重写onTouchEvent方法来对手势进行监听,

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN://按下
            down_y = (int) event.getY();
            break;
        case MotionEvent.ACTION_UP://抬起
            oldy = 0;
            break;
        case MotionEvent.ACTION_MOVE://移动
            moveImageView((int) (event.getY() - down_y));
            break;
    }
    return true;
}

分别对手指按下,抬起,移动进行了处理,按下时获取手指坐标,移动时获取坐标,计算出移动距离,并对图片进行移动,最后返回true,表示在手势完成后,不会再发送给父类进行处理了。

private void moveImageView(int y) {
    if (infoList.size() == 0) {
        return;
    }
    if (y < 0) {//向上滑动
        for (int i = 0; i < infoList.size(); i++) {
            BitmapInfo bitmapInfo = infoList.get(i);
            if (i == 0) {
                if (bitmapInfo.hightTop > (-infoList.size() + 1) * bHeight) {
                    bitmapInfo.setHightTop(bitmapInfo.hightTop + y - oldy);
                    if (bitmapInfo.hightTop < (-infoList.size() + 1) * bHeight) {
                        bitmapInfo.setHightTop((-infoList.size() + 1) * bHeight);
                    }
                }
            } else {
                BitmapInfo lastBitmapInfo = infoList.get(i - 1);
                if (bitmapInfo.hightTop > (-infoList.size() + i + 1) * bHeight && lastBitmapInfo.hightTop <= -(4 - i) * bHeight / 4) {
                    bitmapInfo.setHightTop(bitmapInfo.hightTop + y - oldy);
                    if (bitmapInfo.hightTop < (-infoList.size() + i + 1) * bHeight) {
                        bitmapInfo.setHightTop((-infoList.size() + i + 1) * bHeight);
                    }
                }
            }
        }
    } else {//向下滑动
        for (int i = list.size() - 1; i >= 0; i--) {
            BitmapInfo bitmapInfo = infoList.get(i);
            if (bitmapInfo.hightTop < i * bHeight / 4) {
                bitmapInfo.setHightTop(bitmapInfo.hightTop + y - oldy);
                if (bitmapInfo.hightTop > i * bHeight / 4) {
                    bitmapInfo.setHightTop(i * bHeight / 4);
                }
            }
        }
    }
    oldy = y;
    ViewGroup.LayoutParams layoutParams = this.getLayoutParams();
    layoutParams.height = bHeight + infoList.get(infoList.size() - 1).hightTop;
    this.setLayoutParams(layoutParams);
    invalidate();
}

由于在移动图片是会用到上一步移动的距离oldy,所以在抬起手指的手势处理中多oldy进行初始化,为了更好的处理图片移动时,位置的变化,我用了一个内部bean类来记录图片的位置信息,

private class BitmapInfo {
    private int widthLeft;
    private int hightTop;
    private int widthRight;
    private int hightBottom;

    BitmapInfo(int widthLeft, int hightTop, int widthRight, int hightBottom) {
        this.widthLeft = widthLeft;
        this.hightTop = hightTop;
        this.widthRight = widthRight;
        this.hightBottom = hightBottom;
    }

    void setHightTop(int hightTop) {
        this.hightTop = hightTop;
    }
}

到这里控件其实已经完成了,不过在我们把控件放到ScrollView中时,我们会发现我们的图片滑动不了,我们的手指触摸事件被ScrollView屏蔽了,这里我们就要在对应的触摸事件中队父控件的屏蔽事件进行屏蔽,

getParent().requestDisallowInterceptTouchEvent(true);//屏蔽父类的事件屏蔽

,到这里整个控件就大功告成了。

总结:这是一个很简单的控件,没有花哨的效果,这里面会用到Android自定义控件及事件分发机制的知识。

这边是源码:https://github.com/flychen11/MySlideImageView.git


猜你喜欢

转载自blog.csdn.net/flychen11/article/details/79963625