I have a strange problem in my android app. I have an activity which shows an image. The image is saved on the SD card. The user can choose share from the context menu which is coded with the standard ACTION_SEND code. Please see below
public void shareImage(){
Intent emailShare = new Intent(android.content.Intent.ACTION_SEND);
emailShare.setType("image/jpeg");
emailShare.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
emailShare.putExtra(Intent.EXTRA_STREAM,uriId);
startActivity(Intent.createChooser(emailShare,"Send picture using:"));
}
Where uriId is the uri of the image.
This works and the image can be sent to facebook or whatever. But if I then exit my app, rotate the screen the image is missing. I get a file io error in the log when i try and retrieve the image. I have used Astro to search for the image but it is nowhere to be found!
I will post the entire class below. If anyone has any ideas I would be very appreciative.
Stephen
'package com.pengilleys.fishingsnapz;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.FloatMath;
import android.util.Log;
import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import android.widget.TextView;
public class ImagePreview extends Activity implements OnTouchListener{
protected Context mContext;
static final String TAG = "ImagePreview";
static final int SHARE_ID = 0;
static final int EDIT_ID = 1;
static final int PROGRESS_DIALOG = 0;
ProgressDialog progressDialog;
private Bundle extras;
protected static Bitmap bm;
protected DBAdapter db = new DBAdapter(ImagePreview.this);
Long id;
private FacebookManager fb;
private Uri uriId;
//Touch gesture related variables
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 0;
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image_view);
mContext = this;
try{
extras = getIntent().getExtras();
id = (Long) extras.get(DBAdapter.KEY_ROWID);
Log.d(TAG,"id="+id);
ImageView imageV = (ImageView)findViewById(R.id.image_preview);
imageV.setOnTouchListener(this);
//get image
bm = getImage(id);
imageV.setImageBitmap(bm);
imageV.setImageMatrix(matrix);
//get snap details for text overlay
ArrayList<String> details = new ArrayList<String>();
details = getSnapDetails(id);
prepareSnapDetails(details);
}catch(Exception e){
Log.e(TAG,e.toString());
}finally{
}
}
private ArrayList<String> getSnapDetails(long id){
ArrayList<String> fishDetails = new ArrayList<String>();
Cursor cursor;
//open the database and grab the snap details
db.open();
cursor = db.fetchNote(id);
db.close();
//loop through cursor results and put into our arraylist<string>
try{
startManagingCursor(cursor);
cursor.moveToFirst();
//only one row but multiple columns, manually assign columns
String value = cursor.getString(cursor.getColumnIndexOrThrow("date"));
value = checkValue(value);
fishDetails.add(value);
value = cursor.getString(cursor.getColumnIndexOrThrow("type"));
value = checkValue(value);
fishDetails.add(value);
value = cursor.getString(cursor.getColumnIndexOrThrow("weight"));
value = checkValue(value);
fishDetails.add(value);
value = cursor.getString(cursor.getColumnIndexOrThrow("place"));
value = checkValue(value);
fishDetails.add(value);
}catch(Exception e){
Log.e(TAG,e.toString());
}
db.close();
return fishDetails;
}
private String checkValue(String value){
if(value==""){value="-";};
return value;
}
private boolean prepareSnapDetails(ArrayList<String> details){
TextView tx = (TextView)findViewById(R.id.details_overlay);
tx.setText("");
String detail="";
String[] labels = new String[]{"Date: ","Type: ","Weight: ","Place: "};
try{
for(int i=0;i<4;i++){
//add text details to textview
detail = labels[i] + details.get(i) + '\n';
Log.d(TAG,detail);
CharSequence ch = detail.subSequence(0,detail.length());
tx.append(ch);
}
}catch(Exception e){
Log.e(TAG,e.toString());
}
return true;
}
private Bitmap getImage(Long id){
try{
db.open();
Cursor c = db.fetchUri(id);
uriId = Uri.parse(c.getString(c.getColumnIndexOrThrow(DBAdapter.KEY_URI)));
ContentResolver cr = getContentResolver();
Bitmap bitmap = MediaStore.Images.Media.getBitmap(cr,uriId);
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
if(bitmap.getWidth() > width || bitmap.getHeight() > height){
float heightRatio = (float) height / bitmap.getHeight();
float widthRatio = (float) width / bitmap.getWidth();
Log.d(TAG,"height="+heightRatio + " width=" + widthRatio);
matrix.setScale(widthRatio, heightRatio);
}else{
matrix.setTranslate(1f,1f);
Log.d(TAG,"bitmap.getWidth="+bitmap.getWidth() + " vs width="+width);
Log.d(TAG,"bitmap.getHeight="+bitmap.getHeight() + " vs height="+height);
}
db.close();
return bitmap;
} catch (FileNotFoundException e) {
Log.e("GETIMAGE",e.toString());
return null;
} catch (IOException e) {
Log.e("GETIMAGE",e.toString());
return null;
}catch(Exception e){
Log.e("GETIMAGE",e.toString());
return null;
}
}
public void shareImage(){
Intent emailShare = new Intent(android.content.Intent.ACTION_SEND);
emailShare.setType("image/jpeg");
emailShare.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
emailShare.putExtra(Intent.EXTRA_STREAM,uriId);
startActivity(Intent.createChooser(emailShare,"Send picture using:"));
}
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
final float MIN_ZOOM = 0.25f;
final float MAX_ZOOM = 4;
float height = view.getDrawable().getIntrinsicHeight();
float width = view.getDrawable().getIntrinsicWidth();
float[] matrixValues = new float[9];
RectF viewRect = new RectF(0, 0, view.getWidth(), view.getHeight());
dumpEvent(event);
switch(event.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
Log.d(TAG,"mode=DRAG");
mode=DRAG;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_DOWN:
oldDist=spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if(oldDist>10f){
savedMatrix.set(matrix);
midPoint(mid,event);
mode=ZOOM;
Log.d(TAG,"mode=ZOOM");
}
break;
case MotionEvent.ACTION_MOVE:
if(mode==DRAG){
Log.d(TAG,"mode=MOVE");
matrix.set(savedMatrix);
// limit pan
matrix.getValues(matrixValues);
float currentY = matrixValues[Matrix.MTRANS_Y];
float currentX = matrixValues[Matrix.MTRANS_X];
float currentScale = matrixValues[Matrix.MSCALE_X];
float currentHeight = height * currentScale;
float currentWidth = width * currentScale;
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
float newX = currentX+dx;
float newY = currentY+dy;
RectF drawingRect = new RectF(newX, newY, newX+currentWidth, newY+currentHeight);
float diffUp = Math.min(viewRect.bottom-drawingRect.bottom, viewRect.top-drawingRect.top);
float diffDown = Math.max(viewRect.bottom-drawingRect.bottom, viewRect.top-drawingRect.top);
float diffLeft = Math.min(viewRect.left-drawingRect.left, viewRect.right-drawingRect.right);
float diffRight = Math.max(viewRect.left-drawingRect.left, viewRect.right-drawingRect.right);
if(diffUp > 0 ){
dy +=diffUp;
}
if(diffDown < 0){
dy +=diffDown;
}
if( diffLeft> 0){
dx += diffLeft;
}
if(diffRight < 0){
dx += diffRight;
}
matrix.postTranslate(dx, dy);
}else if(mode==ZOOM){
float newDist= spacing(event);
if(newDist>10f){
matrix.set(savedMatrix);
float scale = newDist / oldDist;
Log.d(TAG,"Scale="+scale);
matrix.getValues(matrixValues);
float currentScale = matrixValues[Matrix.MSCALE_X];
Log.d(TAG,"currentScale="+currentScale);
// limit zoom
if (scale * currentScale > MAX_ZOOM) {
scale = MAX_ZOOM / currentScale;
} else if (scale * currentScale < MIN_ZOOM) {
scale = MIN_ZOOM / currentScale;
}
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
//perform the transformation
view.setImageMatrix(matrix);
return true;
}
private static float spacing(MotionEvent event){
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private static void midPoint(PointF point, MotionEvent event){
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
/** Show an event in the logcat view for debugging **/
private void dumpEvent(MotionEvent event){
String names[] = {"DOWN","UP","MOVE","CANCEL","OUTSIDE","POINTER_DOWN","POINTER_UP","7?","8?","9?"};
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if(actionCode==MotionEvent.ACTION_POINTER_DOWN
|| actionCode==MotionEvent.ACTION_POINTER_UP){
sb.append("pid ").append(
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")");
};
sb.append(" [");
for(int i=0;i < event.getPointerCount();i++){
sb.append("#").append(i);
sb.append("(pid ").append(event.getPointerId(i));
sb.append(")=").append((int) event.getX(i));
sb.append(",").append((int) event.getY(i));
if(i+1 < event.getPointerCount())
sb.append(";");
}
sb.append("]");
Log.d("DUMP", sb.toString());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, SHARE_ID, 0, R.string.share_id);
menu.add(0,EDIT_ID,0,R.string.edit_details);
return true;
}
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch(item.getItemId()) {
case SHARE_ID:
try{
shareImage();
}catch(Exception e){
Log.e(TAG,e.toString());
}
return true;
case EDIT_ID:
try{
Intent intent = new Intent(mContext,SnapDetails.class);
intent.putExtra(DBAdapter.KEY_ROWID,id);
startActivityForResult(intent,FishingSnapz.SNAP_EDIT);
}catch(Exception e){
Log.e(TAG,e.toString());
}
}
return super.onMenuItemSelected(featureId, item);
}
#Override
protected void onResume(){
super.onResume();
}
#Override
protected void onActivityResult (int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
//Required by facebook single sign on - check that we are returning to activity from FB
if(data!=null){
fb.authorizeCallback(requestCode, resultCode, data);
}else{
extras = getIntent().getExtras();
id = (Long) extras.get(DBAdapter.KEY_ROWID);
//get snap details for text overlay
ArrayList<String> details = new ArrayList<String>();
details = getSnapDetails(id);
prepareSnapDetails(details);
}
}
}
'
Sounds like a bug in whatever app you are using to share it with. You might consider making a spare copy of the file before issuing the ACTION_SEND, then deleting the spare copy later if it is still hanging around.
This happens when sharing an image via Facebook. Do this:
1 make a copy,
2 share the copy,
3 delete the copy.
Related
I have a out of memory problem here in which i have full screen images being displayed. I want to show images in full screen and I have two buttons to cycle through them to the left or to the right. How can i have the past images be recycled before showing the next to prevent the out of memory exception? or is there an even better way to do so?
here is my class in which i view the image.
public class ImageViewActivity extends Activity
{
private Button btnHome;
private Button btnBack;
private ImageButton btnLeft;
private ImageButton btnRight;
ImageView imageView;
RelativeLayout layout;
int height;
int width;
Bitmap bitmap;
String[] imagesPath;
int position;
// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
String savedItemClicked;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.imageview_activity);
btnHome = (Button) findViewById(R.id.btnHome);
btnBack = (Button) findViewById(R.id.btnBack);
btnLeft = (ImageButton) findViewById(R.id.leftArrow);
btnRight = (ImageButton) findViewById(R.id.rightArrow);
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
height = displayMetrics.heightPixels;
width = displayMetrics.widthPixels;
imagesPath = getIntent().getStringExtra("IMAGES").split("\\|");
position = getIntent().getIntExtra("POSITION", 0);
bitmap = BitmapFactory.decodeFile(imagesPath[position]);
imageView = (ImageView)findViewById(R.id.displayImage);
imageView.setImageBitmap(Bitmap.createScaledBitmap(bitmap, width, height, false));
btnLeft.setOnClickListener(new View.OnClickListener()
{
public void onClick(View arg0)
{
if (position == 0)
position = 5;
else
position--;
RectF imageRectF = new RectF(0, 0, width, height);
RectF viewRectF = new RectF(0, 0, width, height);
matrix.setRectToRect(imageRectF, viewRectF, Matrix.ScaleToFit.CENTER);
bitmap = BitmapFactory.decodeFile(imagesPath[position]);
ImageView imageView = (ImageView)findViewById(R.id.displayImage);
imageView.setImageBitmap(Bitmap.createScaledBitmap(bitmap, width, height, false));
imageView.setImageMatrix(matrix);
}
});
btnRight.setOnClickListener(new View.OnClickListener()
{
public void onClick(View arg0)
{
if (position == 5)
position = 0;
else
position++;
RectF imageRectF = new RectF(0, 0, width, height);
RectF viewRectF = new RectF(0, 0, width, height);
matrix.setRectToRect(imageRectF, viewRectF, Matrix.ScaleToFit.CENTER);
bitmap = BitmapFactory.decodeFile(imagesPath[position]);
ImageView imageView = (ImageView)findViewById(R.id.displayImage);
imageView.setImageBitmap(Bitmap.createScaledBitmap(bitmap, width, height, false));
imageView.setImageMatrix(matrix);
}
});
btnHome.setOnClickListener(new View.OnClickListener()
{
public void onClick(View arg0)
{
Intent ActivitySwitch = new Intent(getApplicationContext(), MainMenuActivity.class);
startActivity(ActivitySwitch);
}
});
btnBack.setOnClickListener(new View.OnClickListener()
{
public void onClick(View arg0)
{
Intent ActivitySwitch = new Intent(getApplicationContext(), AddClientActivity.class);
startActivity(ActivitySwitch);
}
});
imageView.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
ImageView view = (ImageView) v;
dumpEvent(event);
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
// ...
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY()
- start.y);
} else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
view.setImageMatrix(matrix);
return true;
}
});
}
private void dumpEvent(MotionEvent event) {
String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE",
"POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
sb.append("(pid ").append(
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")");
}
sb.append("[");
for (int i = 0; i < event.getPointerCount(); i++) {
sb.append("#").append(i);
sb.append("(pid ").append(event.getPointerId(i));
sb.append(")=").append((int) event.getX(i));
sb.append(",").append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";");
}
sb.append("]");
}
/** Determine the space between the first two fingers */
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float)Math.sqrt(x * x + y * y);
}
/** Calculate the mid point of the first two fingers */
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
thank you for any input and if you need any additional information please feel free to ask!
I would either scale down the image or consider using the Picasso image loading library: http://square.github.io/picasso/
It is also really simply to use and prevents a lot Out of Memory Exceptions.
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
it was a lot simpler then i first imagined. i simply added this
bitmap.recycle();
before i declared my bitmap to the new image.
I have created simple app with pinch zoom, panning and rotation. They are working very well but not the rotation in your position.
I have used Matrix class.
My Activity code
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
Matrix saveMatrix = new Matrix();
private ImageView viewImage;
private Button btnCapture;
private static final int RESULT_LOAD_IMAGE = 1;
private static final int REQUEST_IMAGE_CAPTURE = 2;
Matrix matrix = new Matrix();
private Uri mCapturedImageURI;
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
private float d = 0f;
private float newRot = 0f;
private float[] lastEvent = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnCapture = (Button) findViewById(R.id.btnCapture);
viewImage = (ImageView) findViewById(R.id.viewImage);
viewImage.setOnTouchListener(MainActivity.this);
initListerner();
}
public void initListerner() {
btnCapture.setVisibility(View.VISIBLE);
btnCapture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
btnCapture.setVisibility(View.GONE);
final Dialog dialog = new Dialog(MainActivity.this);
dialog.setContentView(R.layout.custom_dialog_box);
dialog.setTitle("Title...");
Button dialogButton = (Button) dialog.findViewById(R.id.btnExit);
dialogButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
Button btnChoosePath = (Button) dialog.findViewById(R.id.btnChoosePath);
btnChoosePath.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
activeGallery();
dialog.dismiss();
}
});
Button btnTakePhoto = (Button) dialog.findViewById(R.id.btnTakePhoto);
btnTakePhoto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
activeTakePhoto();
dialog.dismiss();
}
});
dialog.show();
}
});
}
#Override
public void onBackPressed() {
super.onBackPressed();
btnCapture.setVisibility(View.VISIBLE);
}
private void activeTakePhoto() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
String fileName = "temp.jpg";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, fileName);
mCapturedImageURI = getContentResolver()
.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
values);
takePictureIntent
.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
private void activeGallery() {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RESULT_LOAD_IMAGE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case RESULT_LOAD_IMAGE:
if (requestCode == RESULT_LOAD_IMAGE &&
resultCode == RESULT_OK && null != data) {
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver()
.query(selectedImage, filePathColumn, null, null,
null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
viewImage.setImageBitmap(BitmapFactory.decodeFile(picturePath));
}
case REQUEST_IMAGE_CAPTURE:
if (requestCode == REQUEST_IMAGE_CAPTURE &&
resultCode == RESULT_OK) {
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor =
getContentResolver().query(mCapturedImageURI, projection, null,
null, null);
int column_index_data = cursor.getColumnIndexOrThrow(
MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String picturePath = cursor.getString(column_index_data);
cursor.close();
viewImage.setImageBitmap(BitmapFactory.decodeFile(picturePath));
}
}
}
#Override
public boolean onTouch(View v, MotionEvent motionEvent) {
ImageView view = (ImageView) v;
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
saveMatrix.set(matrix);
start.set(motionEvent.getX(), motionEvent.getY());
mode = DRAG;
lastEvent = null;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(motionEvent);
if (oldDist > 10f) {
saveMatrix.set(matrix);
midPoint(mid, motionEvent);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = motionEvent.getX(0);
lastEvent[1] = motionEvent.getX(1);
lastEvent[2] = motionEvent.getY(0);
lastEvent[3] = motionEvent.getY(1);
d = rotation(motionEvent);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(saveMatrix);
float dx = motionEvent.getX() - start.x;
float dy = motionEvent.getY() - start.y;
matrix.postTranslate(dx, dy);
} else if (mode == ZOOM) {
float newDist = spacing(motionEvent);
if (newDist > 10f) {
matrix.set(saveMatrix);
float scale = (newDist / oldDist);
matrix.postScale(scale, scale, mid.x, mid.y);
}
if (lastEvent != null && motionEvent.getPointerCount() == 2) {
newRot = rotation(motionEvent);
float r = newRot - d;
float[] values = new float[9];
matrix.getValues(values);
float tx = values[2];
float ty = values[5];
float sx = values[0];
float xc = (view.getWidth() / 2) * sx;
float yc = (view.getHeight() / 2) * sx;
matrix.postRotate(r, tx + xc, ty + yc);
}
}
break;
}
view.setImageMatrix(matrix);
return true;
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
}
Goal
An activity is made to view image, we can pinch zoom or pan the image. The image is centered in the screen in the beginning. Pinch zoom is centered at the center of the image, even after the image is panned somewhere else in the screen.
The image for displaying is downloaded from a given URL, and the URL is passed from extra of an intent to start the image viewing activity.
Pinch zoom is implemented by postScale(), pan by postTranslate().
Problem
After panning the image somewhere, the pinch-zoom center is still at the center of the screen. Tried to follow the center of the image when it's been moved to a new place but my code doesn't work that way. Please give some idea.
The image downloading and panning work well.
Code
activity_image_viewer_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:background="#color/MyPureBlack" >
<LinearLayout
android:id="#+id/progressbar_wrapper"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ProgressBar
android:id="#+id/progressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="0"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_gravity="center" >
</ProgressBar>
</LinearLayout>
<ImageView
android:id="#+id/image_viewer"
android:visibility="gone"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/MyPureBlack"
android:scaleType="matrix" >
</ImageView>
</LinearLayout>
</FrameLayout>
ActivityImageViewer.java
package com.com2us.hubapp.android;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import org.apache.http.util.ByteArrayBuffer;
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.FloatMath;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.AlphaAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
public class ActivityImageViewer extends Activity {
File imageFile = null;
// Matrices for pinch zoom and pan
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
Matrix savedMatrixZoom = new Matrix();
// State of motion event
static final int NONE = 0;
static final int PAN = 1;
static final int PINCH_ZOOM = 2;
int mode = NONE;
// The first pointer down
PointF start = new PointF();
// The center of the image (Failed to track it when the image has been moved)
PointF centerOfImage = new PointF();
// oldest is the Cartesian distance between first two pointers when the second pointer is down
float oldDist = 1f;
// MIN_SCALE/MAX_SCALE is the min/max scale factor
private final float MIN_SCALE = 0.5f;
private final float MAX_SCALE = 3.0f;
// TOUCH_SENSITIVE is the minimum Cartesian distance between the first two pointers that triggers the pinch zoom
private final float TOUCH_SENSITIVE = 10.0f;
private final float SPACING_LEFT_AND_RIGHT = 30.0f;
private final float SPACING_TOP_AND_BOTTOM = 30.0f;
// The ImageView widget
private ImageView image_viewer;
// The progress bar shows what current progress is before the image downloading is completed
private ProgressBar progressbar;
private LinearLayout progressbar_wrapper;
// An async task that downloads the image from a given URL
private DownloadFilesTask downloadFilesTask;
private class DownloadFilesTask extends AsyncTask<String, Integer, Bitmap> {
protected Bitmap doInBackground(String... urls) {
InputStream input = null;
OutputStream output = null;
try {
URL url = new URL(urls[0]);
URLConnection connection = url.openConnection();
connection.connect();
int lenghtOfFile = connection.getContentLength();
// download the file
InputStream is = connection.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is, 8190);
ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
while ((current = bis.read()) != -1) {
baf.append((byte)current);
}
byte[] imageData = baf.toByteArray();
Bitmap bmp = BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
//final int percent = (int) (total * 100 / lenghtOfFile);
//publishProgress(percent);
//lenghtOfFile
return bmp;
} catch (Exception e) {
} finally {
try {
if (output != null)
output.close();
output = null;
} catch (IOException e) {
}
try {
if (input != null)
input.close();
input = null;
} catch (IOException e) {
}
}
return null;
} // protected Bitmap doInBackground(String... urls) {}
protected void onProgressUpdate(Integer... progress) {
progressbar.setProgress(progress[0]);
}
protected void onPostExecute(Bitmap bmp) {
if (bmp != null) {
final AlphaAnimation animationAfter = new AlphaAnimation(0.0f, 1.0f);
animationAfter.setDuration(300);
animationAfter.setFillEnabled(true);
animationAfter.setFillAfter(true);
image_viewer.setAnimation(animationAfter);
image_viewer.setImageBitmap(bmp);
ViewTreeObserver viewTreeObserver = image_viewer.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Drawable drawable = image_viewer.getDrawable();
int dx = (image_viewer.getWidth() - drawable.getIntrinsicWidth()) / 2;
int dy = (image_viewer.getHeight() - drawable.getIntrinsicHeight()) / 2;
matrix.postTranslate(dx, dy);
image_viewer.setImageMatrix(matrix);
}
});
progressbar_wrapper.setVisibility(View.GONE);
image_viewer.setVisibility(View.VISIBLE);
} else {
android.os.Handler handler = new android.os.Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
finish();
}
}, 2000);
}
} // End of protected void onPostExecute(Bitmap bmp) {}
} // End of private class DownloadFilesTask extends AsyncTask<String, Integer, Bitmap> {}
// These are activity life cycle handling
// onCreate
#Override
public void onCreate(Bundle savedInstanceState) {
//setTheme(R.style.HubTheme);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_viewer);
progressbar_wrapper = (LinearLayout) findViewById(R.id.progressbar_wrapper);
image_viewer = (ImageView) findViewById(R.id.image_viewer);
progressbar = (ProgressBar) findViewById(R.id.progressbar);
image_viewer.setOnTouchListener(new MyOnTouchListener());
final String uriForImage = getIntent().getStringExtra("url");
downloadFilesTask = new DownloadFilesTask();
downloadFilesTask.execute(uriForImage);
}
// onStart
#Override
protected void onStart() {
super.onStart();
}
// onResume
#Override
protected void onResume() {
super.onResume();
}
// onPause
#Override
protected void onPause() {
super.onPause();
}
// onStop
#Override
protected void onStop() {
super.onStop();
}
// onRestart
#Override
protected void onRestart() {
super.onRestart();
}
// onDestroy
#Override
protected void onDestroy() {
super.onDestroy();
if (imageFile != null) {
try {
Drawable drawable = image_viewer.getDrawable();
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
Bitmap bitmap = bitmapDrawable.getBitmap();
bitmap.recycle();
drawable = null;
bitmapDrawable = null;
bitmap = null;
} catch (NullPointerException e) {
}
}
}
// onKeyDown
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
this.onBackPressed();
}
return true;
}
// onBackPressed
public void onBackPressed() {
finish();
}
// onConfigurationChanged
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.equals(Configuration.ORIENTATION_LANDSCAPE)) {
} else if (newConfig.equals(Configuration.ORIENTATION_PORTRAIT)) {
}
}
// onLowMemory
#Override
public void onLowMemory() {
super.onLowMemory();
finish();
}
// Get the Cartesian distance between the first two pointers
private float spacing(MotionEvent event) {
float x = 0;
float y = 0;
try {
Method getX = MotionEvent.class.getMethod("getX", Integer.TYPE);
Method getY = MotionEvent.class.getMethod("getX", Integer.TYPE);
// x = event.getX(0) - event.getX(1);
// y = event.getY(0) - event.getY(1);
float x1 = (Float) getX.invoke(event, 0);
float x2 = (Float) getX.invoke(event, 1);
x = x1 - x2;
float y1 = (Float) getY.invoke(event, 0);
float y2 = (Float) getY.invoke(event, 1);
y = y1 - y2;
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
return FloatMath.sqrt(x * x + y * y);
}
// Some flags set manually for convenience
private final int MotionEvent_ACTION_MASK = 255; // that is 0xFF or 11111111
private final int MotionEvent_ACTION_POINTER_DOWN = 5; // that is 101
private final int MotionEvent_ACTION_POINTER_UP = 6; // that is 110
private class MyOnTouchListener implements OnTouchListener {
// onTouch
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
Drawable drawable = view.getDrawable();
if (drawable == null)
return true;
switch (event.getAction() & MotionEvent_ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = PAN;
break;
case MotionEvent_ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > TOUCH_SENSITIVE) {
savedMatrix.set(matrix);
mode = PINCH_ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent_ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if (mode == PAN) {
// /////////////////////////////////////////
matrix.set(savedMatrix);
float[] matrixValues = new float[9];
Rect viewRect = new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
matrix.getValues(matrixValues);
float currentY = matrixValues[Matrix.MTRANS_Y];
float currentX = matrixValues[Matrix.MTRANS_X];
float currentScale = matrixValues[Matrix.MSCALE_X];
float currentHeight = drawable.getIntrinsicHeight() * currentScale;
float currentWidth = drawable.getIntrinsicWidth() * currentScale;
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
float newX = currentX + dx;
float newY = currentY + dy;
RectF drawingRect = new RectF(newX, newY, newX + currentWidth, newY + currentHeight);
float diffUp = Math.min(viewRect.bottom - drawingRect.bottom, viewRect.top - drawingRect.top) - SPACING_TOP_AND_BOTTOM;
float diffDown = Math.max(viewRect.bottom - drawingRect.bottom, viewRect.top - drawingRect.top) + SPACING_TOP_AND_BOTTOM;
float diffLeft = Math.min(viewRect.left - drawingRect.left, viewRect.right - drawingRect.right) - SPACING_LEFT_AND_RIGHT;
float diffRight = Math.max(viewRect.left - drawingRect.left, viewRect.right - drawingRect.right) + SPACING_LEFT_AND_RIGHT;
if (diffUp > 0) {
dy += diffUp;
}
if (diffDown < 0) {
dy += diffDown;
}
if (diffLeft > 0) {
dx += diffLeft;
}
if (diffRight < 0) {
dx += diffRight;
}
matrix.postTranslate(dx, dy);
} else if (mode == PINCH_ZOOM) {
float newDist = spacing(event);
if (newDist > TOUCH_SENSITIVE) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
// Get the center of the image. (Failed to get it when image has been moved)
Rect viewRect = new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
centerOfImage.x = viewRect.centerX();
centerOfImage.y = viewRect.centerY();
float[] f = new float[9];
Matrix tmp = new Matrix(matrix);
tmp.postScale(scale, scale, centerOfImage.x, centerOfImage.y);
tmp.getValues(f);
float scaleX = f[Matrix.MSCALE_X];
if (scaleX < MIN_SCALE || scaleX > MAX_SCALE) {
matrix.set(savedMatrixZoom);
} else {
matrix.postScale(scale, scale, centerOfImage.x, centerOfImage.y);
savedMatrixZoom.set(matrix);
}
}
}
break;
}
view.setImageMatrix(matrix);
return true;
} // End of public boolean onTouch(View v, MotionEvent event) {}
} // End of private class MyOnTouchListener implements OnTouchListener {}
} // End of public class ActivityImageViewer extends Activity {}
You can use the Scale Gesture Detector for pinch to zoom. Instead of creating pinch to zoom from scratch you can do something like following,
public class MyCustomView extends View {
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
public MyCustomView(Context mContext){
...
// View code goes here
...
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
return true;
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.scale(mScaleFactor, mScaleFactor);
...
// onDraw() code goes here
...
canvas.restore();
}
private class ScaleListener
extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
invalidate();
return true;
}
}
}
Note : Your translation will reside in onDraw method to scale an image.
In my program can I move image across screen? Sometimes I am loosing it from site and cannot find it. I wish to add function which will place imag on original position.
My own aproach wich does not work (and related question to it to make it work):
ImageView iv = current;
Matrix matrix = iv.getImageMatrix;
float[] values = new float[9];
matrix.getValues(values);
int a = values[Matrix.MTRANS_X];
int b = values[Matrix.MTRANS_Y];
matrix.postTranslate(-a,-b);
iv.setImageMatrix(matrix);
EDIT: Latest code
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutionException;
import ua.mirkvartir.android.frontend.UILApplication;
import android.app.Activity;
import android.app.Fragment;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.drawable.BitmapDrawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.view.MotionEventCompat;
import android.util.FloatMath;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class ImageShowActivity extends Activity {
int p = 0;
Activity app;
ImageAdapterr ia;
ImageView imView;
int imgPos = 0;
Bitmap bm = null;
int geg = 90;
public int width = 0;
public int hight = 0;
Gallery gallery;
Matrix matrix = new Matrix();
Matrix shift = new Matrix();
private int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
private ScaleGestureDetector mScaleDetector;
private float mLastTouchX = 0;
private float mLastTouchY = 0;
private float mPosX = 0;
private float mPosY = 0;
ImageView current;
public List<ImageView> images;
public int reset = 0;
HashMap<Integer, Bitmap> map = new HashMap<Integer, Bitmap>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image_show);
app = this;
images = new ArrayList<ImageView>(
UILApplication.photo_buffer_big.size());
Log.d("images", UILApplication.photo_buffer_big.size() + "");
Log.d("images", images.size() + "");
gallery = (Gallery) findViewById(R.id.gallery);
// EDGES ARE INVISIBLE
gallery.setHorizontalFadingEdgeEnabled(false);
ia = new ImageAdapterr(this);
gallery.setAdapter(ia);
final int length = UILApplication.photo_buffer_big.size();
Button back_btn = (Button) findViewById(R.id.analitics_back_btn);
back_btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
finish();
}
});
final TextView img_counter_tv = (TextView) findViewById(R.id.img_counter);
img_counter_tv.setText(p + 1 + "/" + length);
Button nextButton = (Button) findViewById(R.id.next_btn);
nextButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (p < length - 1) {
p++;
} else {
p = 0;
}
gallery.setSelection(p, true);
img_counter_tv.setText(p + 1 + "/" + length);
}
});
Button backButton = (Button) findViewById(R.id.back_btn);
backButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (p == 0) {
p = length - 1;
} else {
p--;
}
gallery.setSelection(p, true);
img_counter_tv.setText(p + 1 + "/" + length);
}
});
}
public void rotateS(View v) {
ImageView iv = current;
Bitmap b = ((BitmapDrawable) iv.getDrawable()).getBitmap();
Matrix matrix = new Matrix();
matrix.postRotate(geg);
Bitmap bMapRotate = Bitmap.createBitmap(b, 0, 0, b.getWidth(),
b.getHeight(), matrix, true);
iv.setImageBitmap(bMapRotate);
}
public void extendS(View v) {
reset = 1;
Log.d("restart", "yes");
runOnUiThread(new Runnable() {
public void run() {
View viewToUpdate = gallery.getChildAt(p - gallery.getFirstVisiblePosition());
viewToUpdate.invalidate();
// ia.notifyDataSetChanged();
}
});
}
public static Bitmap resizeBitmap(Bitmap photo, float x, float y) {
try {
// get current bitmap width and height
int width = photo.getWidth();
int height = photo.getHeight();
// determine how much to scale
float scaleWidth = x / width;
float scaleHeight = y / height;
Log.d("aspect3", "w: " + scaleWidth + " h: " + scaleHeight);
// create the matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bitmap
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new bitmap
Bitmap resizebitmap = Bitmap.createBitmap(photo, 0, 0, width,
height, matrix, false);
return resizebitmap;
} catch (NullPointerException e) {
e.printStackTrace();
} catch (OutOfMemoryError e) {
e.printStackTrace();
System.gc();
}
return null;
}
class ImageAdapterr extends BaseAdapter {
/** The parent context */
private Context myContext;
/** Simple Constructor saving the 'parent' context. */
public ImageAdapterr(Context c) {
this.myContext = c;
}
Matrix savedMatrix = new Matrix();
/** Returns the amount of images we have defined. */
public int getCount() {
return UILApplication.photo_buffer_big.size();
}
/* Use the array-Positions as unique IDs */
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
/**
* Returns a new ImageView to be displayed, depending on the position
* passed.
*/
public View getView(final int position, View convertView,
ViewGroup parent) {
ImageView imView = new ImageView(this.myContext);
current = imView;
imgPos = position;
if (bm==null){
AsyncLoad imLoad = new AsyncLoad();
imLoad.execute();
try {
bm = imLoad.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (bm != null) {
imView.setImageBitmap(bm);
} else if (bm == null) {
imView.setImageResource(R.drawable.logo);
}
/* Image should be scaled as width/height are set. */
imView.setScaleType(ImageView.ScaleType.FIT_CENTER);
/* Set the Width/Height of the ImageView. */
imView.setLayoutParams(new Gallery.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
imView.setOnTouchListener(new OnTouchListener() {
private static final String TAG = "Touch";
// These matrices will be used to move and zoom image
PointF start = new PointF();
public PointF mid = new PointF();
// We can be in one of these 3 states
public static final int NONE = 0;
public static final int DRAG = 1;
public static final int ZOOM = 2;
public int mode = NONE;
float oldDist;
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
Log.d(TAG, "mode=DRAG");
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x,
event.getY() - start.y);
} else if (mode == ZOOM) {
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.d(TAG, "mode=NONE");
break;
}
// Perform the transformation
Log.d("point",
(event.getX() - start.x) + " "
+ (event.getY() - start.y));
// Log.d("point",start.x +" "+start.y);
float[] values = new float[9];
matrix.getValues(values);
float a = values[Matrix.MTRANS_X];
float b = values[Matrix.MTRANS_Y];
Log.d("touch matrix", values[Matrix.MPERSP_0] + " "
+ values[Matrix.MPERSP_1] + " "
+ values[Matrix.MPERSP_2]);
Log.d("touch matrix scale", values[Matrix.MSCALE_X] + " "
+ values[Matrix.MSCALE_Y]);
Log.d("touch matrix scew", values[Matrix.MSKEW_X] + " "
+ values[Matrix.MSKEW_Y]);
Log.d("touch matrix trans", values[Matrix.MTRANS_X] + " "
+ values[Matrix.MTRANS_Y]);
if (reset == 1) {
matrix.reset();
savedMatrix.reset();
}
view.setImageMatrix(matrix);
reset = 0;
// images.set(position, view);
return true; // indicate event was handled
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
});
return imView;
}
/**
* Returns the size (0.0f to 1.0f) of the views depending on the
* 'offset' to the center.
*/
public float getScale(boolean focused, int offset) {
/* Formula: 1 / (2 ^ offset) */
return Math.max(0, 1.0f / (float) Math.pow(2, Math.abs(offset)));
}
}
class AsyncLoad extends AsyncTask<Void, Void, Bitmap> {
ProgressDialog pd;
#Override
protected void onPreExecute() {
pd = new ProgressDialog(app);
pd.setOwnerActivity(app);
pd.setTitle("Идет загрузка...");
pd.setCancelable(true);
pd.show();
}
#Override
protected Bitmap doInBackground(Void... arg0) {
// TODO Auto-generated method stub
try {
/*
* Open a new URL and get the InputStream to load data from it.
*/
URL aURL = new URL(UILApplication.photo_buffer_big.get(imgPos));
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
/* Buffered is always good for a performance plus. */
BufferedInputStream bis = new BufferedInputStream(is);
/* Decode url-data to a bitmap. */
bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
/* Apply the Bitmap to the ImageView that will be returned. */
// imView.setImageBitmap(bm);
} catch (IOException e) {
// imView.setImageResource(R.drawable.logo);
bm = null;
Log.e("DEBUGTAG", "Remote Image Exception", e);
}
map.put(imgPos, bm);
Log.d("map", map.size() + "");
return bm;
}
#Override
protected void onPostExecute(Bitmap arg0) {
pd.dismiss();
}
}
}
XML
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/top_tab_bg"
android:padding="10dp" >
<Button
android:id="#+id/analitics_back_btn"
style="#style/ButtonText"
android:layout_marginRight="5dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="#+id/back_btn"
android:background="#drawable/btn_clk_selector"
android:text="Назад" />
<Button
android:id="#+id/btn_rotate"
style="#style/ButtonText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dip"
android:layout_toLeftOf="#+id/analitics_back_btn"
android:background="#drawable/btn_clk_selector"
android:onClick="rotateS"
android:text="Повернуть" />
<Button
android:id="#+id/btn_ex"
style="#style/ButtonText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dip"
android:layout_toLeftOf="#+id/btn_rotate"
android:background="#drawable/btn_clk_selector"
android:onClick="extendS"
android:text="рас" />
<Button
android:id="#+id/next_btn"
style="#style/ButtonText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="5dp"
android:background="#drawable/next_img_btn"
android:paddingRight="10dp" />
<TextView
android:id="#+id/img_counter"
style="#style/ButtonText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="#+id/next_btn"
android:text="1/10" />
<Button
android:id="#+id/back_btn"
style="#style/ButtonText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_toLeftOf="#+id/img_counter"
android:background="#drawable/back_img_btn" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/gal"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<Gallery
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/gallery"
android:adjustViewBounds="true"
android:spacing="10dp"
/>
</RelativeLayout>
</LinearLayout>
EDIT: problem with new code - image is not rested after enlargeS was called. It is reseted after enlargeS call + tab on screen. Also image is partially reseted - it goes to original position and scale, but it goes to its original resolution. So usually i bacamos much smaller then screen, while i need it to fill screen.
Use the code here below:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
RelativeLayout layout = (RelativeLayout) findViewById(R.id.layout);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
imageView = new ImageView(this);
imageView.setLayoutParams(params);
imageView.setImageBitmap(bitmap);
layout.setGravity(Gravity.CENTER_VERTICAL | Gravity.TOP);
layout.addView(imageView);
This will position the ImageView at the center of the RelativeLayout which contains it.
EDIT: see in the code above - I changed the RelativeLayout.LayoutParams to LinearLayout.LayoutParams, because it is the LinearLayout, which contains the RelativeLayout in fact. Now it should work.
Try to use this in your code to set the image view wherever you want on the screen,
iconSMS.setImageResource(R.drawable.ic_launcher_smsmms);
LayoutParams paramsIconSMS = new LayoutParams(iconwidth,iconheight);
iconwidthspacing=(int)Math.round(((float)width/480)*(float)45);
iconheightspacing=(int)Math.round(((float)height/800)*(float)520);
paramsIconSMS.setMargins(iconwidthspacing, iconheightspacing, 0, 0);
iconSMS.setId(204);
iconSMS.setLayoutParams(paramsIconSMS);
Here,
iconwidth=(int)Math.round(width*iconwidthf);
iconheight=(int)Math.round(height*iconheightf);
and width and height variables are,
requestWindowFeature(Window.FEATURE_NO_TITLE);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
width = metrics.widthPixels;
height = metrics.heightPixels;
by width and height you are getting the screen size of your phone in pixels.
i have a bus route map as an image.
using the zoom controller the image is zooming out but not zooming in
please look at my code and let me know the change to be done make it working..
i am developing my app on Gingerbread i.e API 10
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.ZoomControls;
public class Busmaps extends Activity {
ImageView img;
ZoomControls zoom;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.busmaps);
img = (ImageView) findViewById(R.id.imageViewmaps1);
zoom = (ZoomControls) findViewById(R.id.zoomControls1);
zoom.setOnZoomInClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
int w = img.getWidth();
int h = img.getHeight();
RelativeLayout.LayoutParams params =
new RelativeLayout.LayoutParams(w + 50, h + 50);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
img.setLayoutParams(params);
}
});
zoom.setOnZoomOutClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
int w = img.getWidth();
int h = img.getHeight();
RelativeLayout.LayoutParams params =
new RelativeLayout.LayoutParams(w - 50, h - 50);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
img.setLayoutParams(params);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.bus_map_zoom, menu);
return true;
}
}
my xml says for bus route image:-
<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" >
<ImageView
android:id="#+id/imageViewmaps1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="#drawable/map" />
<ZoomControls
android:id="#+id/zoomControls1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
/>
</RelativeLayout>
how should i make my zoom control working for both Zoom in and Zoom out.
Please replace your Zoom in and ZoomOut listener with the following:
zoom.setOnZoomInClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
float x = img.getScaleX();
float y = img.getScaleY();
img.setScaleX((float) (x+1));
img.setScaleY((float) (y+1));
}
});
zoom.setOnZoomOutClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
float x = img.getScaleX();
float y = img.getScaleY();
img.setScaleX((float) (x-1));
img.setScaleY((float) (y-1));
}
});
}
Alternate option is to load the image in the Web view which has build in zoom controller.
As follows:
String page = "<html><body><center><img src=\""+path to your image+"\"/></center></body></html>";
webView.loadDataWithBaseURL("fake",page, "text/html", "UTF-8","");
If you dont want to use the build in web view zoom controller then you can just place your own buttons and apply zoom in and zoom out on web view as follows:
webView.setInitialScale(ZOOM_LEVEL);
public class Busmap extends Activity implements OnTouchListener
{
private static final String TAG = "Touch";
#SuppressWarnings("unused")
private static final float MIN_ZOOM = 1f,MAX_ZOOM = 1f;
// These matrices will be used to scale points of the image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// The 3 states (events) which the user is trying to perform
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// these PointF objects are used to record the point(s) the user is touching
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.busmaps);
ImageView view = (ImageView) findViewById(R.id.imageViewmaps1);
view.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event)
{
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
float scale;
dumpEvent(event);
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN: // first finger down only
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
Log.d(TAG, "mode=DRAG"); // write to LogCat
mode = DRAG;
break;
case MotionEvent.ACTION_UP: // first finger lifted
case MotionEvent.ACTION_POINTER_UP: // second finger lifted
mode = NONE;
Log.d(TAG, "mode=NONE");
break;
case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 5f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)
{
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix of points
}
else if (mode == ZOOM)
{
// pinch zooming
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 5f)
{
matrix.set(savedMatrix);
scale = newDist / oldDist; // setting the scaling of the
// matrix...if scale > 1 means
// zoom in...if scale < 1 means
// zoom out
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
view.setImageMatrix(matrix); // display the transformation on screen
return true; // indicate event was handled
}
private float spacing(MotionEvent event)
{
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event)
{
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}