Gallery + ViewPager实现图片浏览器

本文介绍了一个自定义的图片浏览器实现过程,包括图片切换、浏览、缩放及拖动功能,并解决了ViewPager滑动与图片拖动之间的冲突。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相信很多人在开发中都有做过图片浏览或者是预览的功能,但我想大多数人会和我一样,百度一下仿微信发说说,然后下载个demo,直接把demo拷到自己的代码进行一些简单的修改,完成该有的效果就ok了,从不去仔细的去看别人的代码。再随着越来越多开源框架的出来,我们已习惯了用别人的东西,渐渐的忘记了怎么去写。浑浑噩噩过了这么长时间了,反省了,我也想自己写点东西了,向csdn大神学习。
本文参考http://blog.youkuaiyun.com/lmj623565791/article/details/39480503 鸿洋大神的博客,谢谢;

先分析一下图片预览功能,能够切换并显示图片,对选中的图片进行缩放处理。
首先来第一步:对图片进行切换和浏览
上代码
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        ></android.support.v4.view.ViewPager>
    <Gallery
        android:id="@+id/gallery"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:unselectedAlpha="0.6"
        android:spacing="10dp"
        ></Gallery>
</LinearLayout>
然后是代码,很简单,就是分别给gallery和viewpager设置设配器,然后两者中有一个改变时,切换另一个的=显示条目;
package com.hpl.demo_application;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;

import java.util.ArrayList;

/**
 * Created by 79115 on 2016/12/1.
 */
public class TestActivity extends Activity {
    private int[] images = {R.drawable.icon_001, R.drawable.icon_002, R.drawable.icon_003, R.drawable.icon_004, R.drawable.icon_005, R.drawable.icon_006};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);
        final Gallery gallery = (Gallery) findViewById(R.id.gallery);
        final ViewPager viewpager = (ViewPager) findViewById(R.id.viewpager);
        final ArrayList<View> views = new ArrayList<View>();
        gallery.setAdapter(new BaseAdapter() {
            @Override
            public int getCount() {
                return images.length;
            }

            @Override
            public Object getItem(int i) {
                return null;
            }

            @Override
            public long getItemId(int i) {
                return 0;
            }

            @Override
            public View getView(int i, View view, ViewGroup viewGroup) {
                ImageView imageView = new ImageView(TestActivity.this);
                imageView.setScaleType(ImageView.ScaleType.FIT_XY);
                imageView.setLayoutParams(new Gallery.LayoutParams(100, 75));
                imageView.setImageResource(images[i % images.length]);
                return imageView;
            }
        });

        viewpager.setAdapter(new PagerAdapter() {
            @Override
            public int getCount() {
                return images.length;
            }

            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view == object;
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                ImageView imageView = new ImageView(TestActivity.this);
                imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
                imageView.setImageResource(images[position % images.length]);
                views.add(imageView);
                container.addView(imageView);
                return imageView;
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView(views.get(position));
            }
        });

        viewpager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                int selectedItemPosition = gallery.getSelectedItemPosition();
                if(position != selectedItemPosition)
                gallery.setSelection(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

        gallery.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                int currentItem = viewpager.getCurrentItem();
                if(i != currentItem)
                viewpager.setCurrentItem(i);
            }

            @Override
            public void onNothingSelected(AdapterView<?> adapterView) {

            }
        });
    }
然后,自定义一个ZoomImageView,继承ImageView,直接上代码了,代码里注释的挺详细
package com.hpl.demo_application;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;

/**
 * 可缩放ImageView
 * Created by 79115 on 2016/12/1.
 */
public class ZoomImageView2 extends ImageView implements ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener {
    private final ScaleGestureDetector scaleGestureDetector;
    private Matrix scaleMatrix = new Matrix();
    private final float MAX_SCALE = 4.0f;
    private float initScale = 1.0f;
    private final float[] values = new float[9];
    private boolean once = true;

    public ZoomImageView2(Context context) {
        this(context, null);
    }

    public ZoomImageView2(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ZoomImageView2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //设置图片的缩放模式为矩形显示
        setScaleType(ScaleType.MATRIX);
        //创建ScaleGestureDetector实例
        scaleGestureDetector = new ScaleGestureDetector(context, this);
        //设置图片的触摸监听
        this.setOnTouchListener(this);
    }

    @Override
    public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
        //此次放大的倍数
        float scaleFactor = scaleGestureDetector.getScaleFactor();
        //已经放大到的倍数
        float scale = getScale();
        if(getDrawable() == null){
            return true;
        }
        if((scale < MAX_SCALE && scaleFactor > 1.0f)  //小于最大放大倍数并且放大
                || (scale > initScale && scaleFactor < 1.0f)){ //大于最小倍数并且缩小
            //放大后超过放大倍数,做处理
            if(scale * scaleFactor > MAX_SCALE){
                scaleFactor = MAX_SCALE / scale;
            }
            if(scale * scaleFactor < initScale){
                scaleFactor = initScale / scale;
            }
            //以缩放手势的中心点缩放
            scaleMatrix.postScale(scaleFactor, scaleFactor, scaleGestureDetector.getFocusX(), scaleGestureDetector.getFocusY());
            //检查边缘,当图片边缘放大后再缩小会仅有一部分显示在屏幕上,这时候需要将图片移到屏幕的中间来;
            checkBorder();
            setImageMatrix(scaleMatrix);
        }
        return true;
    }

    private void checkBorder() {
        Matrix matrix = this.scaleMatrix;
        RectF rectF = new RectF();
        float dx = 0, dy = 0;
        if(getDrawable() != null){
            //设置范围
            rectF.set(0, 0 ,getDrawable().getIntrinsicWidth(), getDrawable().getIntrinsicHeight());
            matrix.mapRect(rectF);
            
	if(rectF.width() > getWidth()){
    		if (rectF.left > 0) {
        	dx = -rectF.left;
    	}
    	if (rectF.right < getWidth()) {
       		dx = getWidth() - rectF.right;
    	}
	}
	if (rectF.height() >= getHeight()) {
    		if (rectF.top > 0) {
        	dy = -rectF.top;
    		}
   		 if (rectF.bottom < getHeight()) {
       		 dy = getHeight() - rectF.bottom;
   	 }
	}
// 如果宽或高小于屏幕,则让其居中 if (rectF.width() < getWidth()) { dx = -((rectF.right + rectF.left) / 2) + getWidth() / 2; } if (rectF.height() < getHeight()) { dy = -((rectF.top + rectF.bottom) / 2) + getHeight() / 2; } scaleMatrix.postTranslate(dx, dy); } } private float getScale() { scaleMatrix.getValues(values); return values[Matrix.MSCALE_X]; } @Override public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) { return true; } @Override public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) { } @Override public boolean onTouch(View view, MotionEvent motionEvent) { //将触摸事件交给scaleGestureDetector处理 return scaleGestureDetector.onTouchEvent(motionEvent); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); getViewTreeObserver().addOnGlobalLayoutListener(this); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); getViewTreeObserver().removeOnGlobalLayoutListener(this); } @Override public void onGlobalLayout() { if(once){ Drawable drawable = getDrawable(); if(drawable != null){ //获取控件的宽高 int width = getWidth(); int height = getHeight(); //获取图片的宽高 int dw = drawable.getIntrinsicWidth(); int dh = drawable.getIntrinsicHeight(); //如果图片的宽大于控件的宽,改变初始的缩放比例 if(dw > width && dh <= height){ initScale = width * 1.0f / dw; } //如果图片的高大于控件的高,改变初始的缩放比例 if(dh > height && dw <= width){ initScale = height * 1.0f / dh; } //如果图片的宽高都大于控件的宽高,则取其中比例小的,这样才能将图片显示完全 if(dh > height && dw > width){ initScale = Math.min((width * 1.0f) / dw, (height * 1.0f) / dh); } //将图片移到屏幕中间 scaleMatrix.postTranslate((width - dw) / 2, (height - dh) / 2); //按初始比例以控件中心为原点缩放图片 scaleMatrix.postScale(initScale, initScale, width / 2, height / 2); setImageMatrix(scaleMatrix); } once = false; } }}
将ViewPager构造器里的ImageView替换一下, 效果图如下,截图工具搞了老久,随便截取一下就挺大的,只能草草了事

可以看到这样来我们的图片已经有可缩放能力,但不能够拖动
下面我们开始做屏幕的拖动
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
    //将触摸事件交给scaleGestureDetector处理
    scaleGestureDetector.onTouchEvent(motionEvent);
    if(getDrawable() == null){
        return  true;
    }
    switch (motionEvent.getAction()){
        case MotionEvent.ACTION_DOWN:
            startX = motionEvent.getX();
            startY = motionEvent.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            float x = motionEvent.getX();
            float y = motionEvent.getY();
            float dx = x - startX;
            float dy = y - startY;
            scaleMatrix.postTranslate(dx, dy);
            checkBorder();
            setImageMatrix(scaleMatrix);
            startX = x;
            startY = y;
            break;
        case MotionEvent.ACTION_UP:
            break;
    }
    return true;
}
这里整个图片浏览器基本上算是完成了,但是还得解决一个冲突问题,那就是viewpager的滑动事件和图片的拖动事件的冲突。大家微信什么的用的应该不少,可以发现多数图片预览器是只有当你的图片小于屏幕的时候你才能左右的切换屏幕,所以我们可以在onTouch里面加上这样的判断;
Matrix matrix = this.scaleMatrix;
RectF rectF = new RectF();
    //设置范围
rectF.set(0, 0 ,getDrawable().getIntrinsicWidth(), getDrawable().getIntrinsicHeight());

 if(rectF.width() > getWidth() || rectF.height() > getHeight()){
    //请求父类不拦截事件
    getParent().requestDisallowInterceptTouchEvent(true);
}
这样冲突就解决了,下面来波福利
好险,差点超过2M了


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值