android自定义view查看高清移动大图

来源:互联网 发布:java多线程与高并发 编辑:程序博客网 时间:2024/04/30 10:09
package com.example.customview01;import android.app.Activity;import android.os.Bundle;import java.io.IOException;import java.io.InputStream;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);LargeImageView  viewById = (LargeImageView ) findViewById(R.id.iv);try {////一般的特别大的图片还需要压缩不模糊都放在资源文件中//InputStream inputstrean=getAssets().open("map.jpg");////获得图片的宽、高//BitmapFactory.Options options=new BitmapFactory.Options();//options.inJustDecodeBounds=true;//这里就是为了精确测量接下来的对象////开始解析流//BitmapFactory.decodeStream(inputstrean,null,options);//通过这一步之后options自动就记录了对象的所有属性(宽高等)//int outWidth = options.outWidth;//int outHeight = options.outHeight;////设置显示图片的中心区域////传入我们需要处理的图片//BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputstrean, false);//BitmapRegionDecoder区域识别//BitmapFactory.Options options1=new BitmapFactory.Options();////对图片来说,每个像素除了有颜色信息外,还可以包含透明度信息。在计算机中透明度用一个单独的通道来表示,通常称为Alpha通道。////并非所有的图片格式都支持透明度,JPEG格式图片不支持透明度,PNG,GIF格式支持透明度。////在Android中通常用一个32位的整数来表示一个像素的颜色和透明度。32位的4个字节从高到低分别表示Alpha,R,G,//// B四个通道,每个通道用8位表示,每个通道的值范围是[0, 0xFF),对Alpha通道0表示完全透明,0xFF表示完全不透明。对R,G,B三个通道,//// 0表示没有该通道的颜色分量,0xFF表示该通道颜色分量达到最大。R,G,B三个通道均为0为黑色,R,G,B三个通道均为0xFF表示白色////BitmapFactory.Options类是BitmapFactory对图片进行解码时使用的一个配置参数类,其中定义了一系列的public成员变量,每个成员变量代表一个配置参数。//// 参数inpreferredconfig表示图片解码时使用的颜色模式,//// 也就是图片中每个像素颜色的表示方式。参数inpreferredconfig的可选值有四个,分别为ALPHA_8,RGB_565,ARGB_4444,ARGB_8888。它们的含义列举如下。////ALPHA_8图片中每个像素用一个字节(8位)存储,该字节存储的是图片8位的透明度值////RGB_565图片中每个像素用两个字节(16位)存储,两个字节中高5位表示红色通道,中间6位表示绿色通道,低5位表示蓝色通道////ARGB_4444图片中每个像素用两个字节(16位)存储,Alpha,R,G,B四个通道每个通道用4位表示////ARGB_8888图片中每个像素用四个字节(32位)存储,Alpha,R,G,B四个通道每个通道用8位表示///*所有情况下ARGB_8888配置都可以满足//所有情况下ALPHA_8配置都不满足//绝大多数情况下RGB565选项都不满足//所以,所谓设置RGB565选项可以减少内存的说法根本不成立,而且在所有RGB565选项可以满足的情况中,//除Android4.4系统以上8位RGB编码的JPG图片(即灰度图)外 ,其他情况使用null选项也会使用RGB565选项。//所以,基本上指定inPreferredConfig为RGB565和不设置inPreferredConfig的效果是一样的。**///options1.inPreferredConfig= Bitmap.Config.ARGB_8888;//显示颜色和透明度//Bitmap bitmap = bitmapRegionDecoder.decodeRegion(new Rect(outWidth / 2 - 100, outHeight / 2 - 100, outWidth / 2 + 100, outHeight / 2 + 100), options);//viewById.setImageBitmap(bitmap);InputStream inputStream = getAssets().open("map.png");    viewById.setInputStream(inputStream);} catch (IOException e) {e.printStackTrace();}}}package com.example.customview01;import android.content.Context;import android.graphics.PointF;import android.view.MotionEvent;/** * Created by zhq_zhao on 2017/8/1. * 这里模仿了系统的ScaleGestureDetector,编写了MoveGestureDetector,代码如下: */public class MoveGestureDetector extends BaseGestureDetector {    private PointF mCurrentPointer;    private PointF mPrePointer;    //用于记录最终结果,并返回    //PointF只是一个类型,可以存储float类型的x,y值。你是要获取屏幕坐标?    // MotionEvent.getX()和getY();可以获取x,y值,可以用PointF类存放。    private PointF mExtenalPointer = new PointF();    private OnMoveGestureListener mListenter;    public MoveGestureDetector(Context context, OnMoveGestureListener listener) {        super(context);        mListenter = listener;    }    /**正在移动操作对象过程中     *     * @param event     */    @Override    protected void handleInProgressEvent(MotionEvent event) {        int actionCode = event.getAction() & MotionEvent.ACTION_MASK;//ACTION_MASK在Android中是应用于多点触摸操作        switch (actionCode) {            case MotionEvent.ACTION_CANCEL:            case MotionEvent.ACTION_UP:                mListenter.onMoveEnd(this);                resetState();//释放资源                break;            case MotionEvent.ACTION_MOVE:                updateStateByEvent(event);                boolean update = mListenter.onMove(this);                if (update) {                    mPreMotionEvent.recycle();                    mPreMotionEvent = MotionEvent.obtain(event);//回收资源还要获取上一个操作对象的状态                }                break;        }    }    /**开始移动     *     * @param event     */    @Override    protected void handleStartProgressEvent(MotionEvent event) {        int actionCode = event.getAction() & MotionEvent.ACTION_MASK;        switch (actionCode) {            case MotionEvent.ACTION_DOWN:                resetState();//防止没有接收到CANCEL or UP ,保险起见                mPreMotionEvent = MotionEvent.obtain(event);                updateStateByEvent(event);                break;            case MotionEvent.ACTION_MOVE:                mGestureInProgress = mListenter.onMoveBegin(this);                break;        }    }    protected void updateStateByEvent(MotionEvent event) {        final MotionEvent prev = mPreMotionEvent;        mPrePointer = caculateFocalPointer(prev);        mCurrentPointer = caculateFocalPointer(event);        //Log.e("TAG", mPrePointer.toString() + " ,  " + mCurrentPointer);        boolean mSkipThisMoveEvent = prev.getPointerCount() != event.getPointerCount();        //Log.e("TAG", "mSkipThisMoveEvent = " + mSkipThisMoveEvent);        mExtenalPointer.x = mSkipThisMoveEvent ? 0 : mCurrentPointer.x - mPrePointer.x;        mExtenalPointer.y = mSkipThisMoveEvent ? 0 : mCurrentPointer.y - mPrePointer.y;    }    /**     * 根据event计算多指中心点     *     * @param event     * @return     */    private PointF caculateFocalPointer(MotionEvent event) {        final int count = event.getPointerCount();        float x = 0, y = 0;        for (int i = 0; i < count; i++) {            x += event.getX(i);            y += event.getY(i);        }        x /= count;        y /= count;        return new PointF(x, y);    }    public float getMoveX() {        return mExtenalPointer.x;    }    public float getMoveY()    {        return mExtenalPointer.y;    }    public interface OnMoveGestureListener {         boolean onMoveBegin(MoveGestureDetector detector);         boolean onMove(MoveGestureDetector detector);         void onMoveEnd(MoveGestureDetector detector);    }    public static class SimpleMoveGestureDetector implements OnMoveGestureListener {        @Override        public boolean onMoveBegin(MoveGestureDetector detector)        {            return true;        }        @Override        public boolean onMove(MoveGestureDetector detector)        {            return false;        }        @Override        public void onMoveEnd(MoveGestureDetector detector) {        }    }}package com.example.customview01;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.BitmapRegionDecoder;import android.graphics.Canvas;import android.graphics.Rect;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import java.io.IOException;import java.io.InputStream;/** * Created by zhq_zhao on 2017/8/1. * 提供一个设置图片的入口 *重写onTouchEvent,在里面根据用户移动的手势,去更新显示区域的参数 * 每次更新区域参数后,调用invalidate,onDraw里面去regionDecoder.decodeRegion拿到bitmap,去draw */public class LargeImageView extends View {    private BitmapRegionDecoder bitmapRegionDecoder;    //图片的宽度和高度    private int mPictureHight;    private int mPictureWith;    //volatile是一个类型修饰符(type specifier)。它是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile,    // 基本上会导致这样的结果:要么无法编写多线程程序,要么编译器失去大量优化的机会。    private volatile Rect mRect=new Rect();//绘制的区域    //图片属性参数    private static BitmapFactory.Options mOptions=new BitmapFactory.Options();    //静态代码块    static {        mOptions.inPreferredConfig= Bitmap.Config.RGB_565;//让操作的图片属性具有透明和颜色值    }    private MoveGestureDetector moveGestureDetector;    //操作输入流    protected void setInputStream(InputStream inputStream)  {        try {      //创建手势识别区域            bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);            //让输入流图片对象属性映射到options            BitmapFactory.Options mOptionss=new BitmapFactory.Options();            mOptionss.inJustDecodeBounds=true;//开启虚拟区域软件加速测量            //快速解析流对象            BitmapFactory.decodeStream(inputStream,null,mOptionss);//通过这一步mOptionss已经装载了图片的各种属性值            //得到图片的宽度和高度            mPictureHight= mOptionss.outHeight;            mPictureWith= mOptionss.outWidth;            //下面是每一次测量需要不断的重庆请求布局排版            requestLayout();            //排版完成后重新绘制在界面上来展示当前的对象            invalidate();        } catch (IOException e) {            e.printStackTrace();        }finally {            //关流,否则导致内存泄漏            if(inputStream!=null){                try {                    inputStream.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }    /*初始化数据     */    public void init() {        moveGestureDetector = new MoveGestureDetector(getContext(), new MoveGestureDetector.SimpleMoveGestureDetector() {            @Override            public boolean onMove(MoveGestureDetector detector) {                int moveX = (int) detector.getMoveX();                int moveY = (int) detector.getMoveY();                if (mPictureWith > getWidth()) {                    mRect.offset(-moveX, 0);                    checkWidth();                    invalidate();                }                if (mPictureHight > getHeight()) {                    mRect.offset(0, -moveY);                    checkHeight();                    invalidate();                }                return true;            }        });    }        private void checkWidth(){            Rect rect = mRect;            int imageWidth = mPictureWith;            int imageHeight = mPictureHight;            if (rect.right > imageWidth)            {                rect.right = imageWidth;                rect.left = imageWidth - getWidth();            }            if (rect.left < 0)            {                rect.left = 0;                rect.right = getWidth();            }        }        private void checkHeight() {            Rect rect = mRect;            int imageWidth = mPictureWith;            int imageHeight = mPictureHight;            if (rect.bottom > imageHeight)            {                rect.bottom = imageHeight;                rect.top = imageHeight - getHeight();            }            if (rect.top < 0)            {                rect.top = 0;                rect.bottom = getHeight();            }        }        public LargeImageView(Context context, AttributeSet attrs)        {            super(context, attrs);            init();        }        @Override        public boolean onTouchEvent(MotionEvent event)        {            moveGestureDetector.onToucEvent(event);            return true;        }        @Override        protected void onDraw(Canvas canvas)        {            Bitmap bm = bitmapRegionDecoder.decodeRegion(mRect, mOptions);            canvas.drawBitmap(bm, 0, 0, null);        }        @Override        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)        {            super.onMeasure(widthMeasureSpec, heightMeasureSpec);            int width = getMeasuredWidth();            int height = getMeasuredHeight();            int imageWidth = mPictureWith;            int imageHeight = mPictureHight;            //默认直接显示图片的中心区域,可以自己去调节            mRect.left = imageWidth / 2 - width / 2;            mRect.top = imageHeight / 2 - height / 2;            mRect.right = mRect.left + width;            mRect.bottom = mRect.top + height;        }}package com.example.customview01;import android.content.Context;import android.view.MotionEvent;/** * Created by zhq_zhao on 2017/8/1. */public abstract class BaseGestureDetector {    protected boolean mGestureInProgress;//是否移动中    protected MotionEvent mPreMotionEvent;//移动前    protected MotionEvent mCurrentMotionEvent;//当前移动的对象属性    protected Context mContext;    public BaseGestureDetector(Context context)    {        mContext = context;    }    public boolean onToucEvent(MotionEvent event) {        if (!mGestureInProgress) {            handleStartProgressEvent(event);//开始移动        } else {            handleInProgressEvent(event);//移动中        }        return true;    }    protected abstract void handleInProgressEvent(MotionEvent event);    protected abstract void handleStartProgressEvent(MotionEvent event);    protected abstract void updateStateByEvent(MotionEvent event);    /**     * 重置当前的操作对象的状态     *     */    protected void resetState() {        if (mPreMotionEvent != null) {            mPreMotionEvent.recycle();//回收掉            mPreMotionEvent = null;        }        if (mCurrentMotionEvent != null) {            mCurrentMotionEvent.recycle();            mCurrentMotionEvent = null;        }        mGestureInProgress = false;//不移动回收掉    }}<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent">    <com.example.customview01.LargeImageView        android:id="@+id/iv"        android:layout_width="match_parent"        android:layout_height="match_parent"/></RelativeLayout>来自:http://blog.csdn.net/lmj623565791/article/details/49300989; 

阅读全文
0 0
原创粉丝点击