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
- android自定义view查看高清移动大图
- Android 加载高清大图
- android大图、高清图片处理
- android处理大图、高清图像的方法
- 一招解决Android 加载高清大图
- Android 高清加载长图或大图方案
- Android中加载高清大图及图片压缩方式
- 【Android】显示高清大图,可缩放类库
- 加载高清大图(本地、在线)---使用subsampling-scale-image-view
- Android View 查看大图(支持拖拽,缩放,旋转)
- Android之---自定义view显示一张高清的原图(不压缩,支持拖动,可拓展至缩放手势)
- 网络安全培训笔记 (高清大图)
- AsyncLoadLocalImage ios 加载本地高清大图
- Android 自定义 按当前view的宽高进行矩形移动内容图
- Android 大图查看器
- Android之打造自己加载高清大图及瀑布流框架.解决错位等问题.
- MVP模式在Android中的应用(附UML高清大图,使用RecyclerView举例)
- 浅谈android中加载高清大图及图片压缩方式(二)
- openfire(1)
- Eclipse4插件开发实现自定义工具栏
- View工作原理
- nvidia 硬件条件下 ffmpeg安装流程
- MyEclipse2014搭建SSH框架
- android自定义view查看高清移动大图
- Android游戏开发之地图编辑器的使用以及绘制地图
- 用u盘安装kali2.0时出现的问题的个人解决方案
- ElasticSearch配置文件解析
- Jquery跳出each循环的解决办法
- Java中的变量与常量、基本数据类型及其类型转换
- [算法与数据结构]
- Node.js程序配置使用Nginx服务器(2017.11.17添加https)
- 【DL--12】Theano入门