B4A Library TouchImageView

TouchImageView is an updated version of ImageView.
It adds support for touch events - drag and pinch zoom.

On devices with an Android version older than Eclair 2.0 and on devices without multitouch support only drag will be supported.
The same also applies when using the emulator.


Reference

Events:
TouchImageView generates no events.
Note however that the Click and LongClick events generated by the standard ImageView WILL be generated if the TouchImageView TouchEnabled property is False.
If TouchEnabled is set to True then the standard Click and LongClick events will NOT be generated.

Methods and properties:

CreateLog

Creates log entries with details about the current state of the TouchImageView, for debugging purposes:

** TouchImageView.CreateLog **
Original image: width = 962, height = 962
Scaled image: width = 294, height = 294
Translate position: x = 172, y = 346
ScaleX = 0.30614918, ScaleY = 0.30614918

MinScale As Float

Get or set the minimum scale that the image can be reduced by (zoomed out).
Default MinScale is 0.5.

B4X:
TouchImageView1.MinScale = 0.25

MaxScale As Float

Get or set the maximum scale that the image can be enlarged by (zoomed in).
Default MaxScale is 2.5.

B4X:
TouchImageView1.MaxScale = 3.75

GetScaleRect As anywheresoftware.b4a.objects.drawable.CanvasWrapper.RectWrapper

Returns a Rect that describes the current scale and position of the image.
You can get use this ScaleRect to restore a TouchImageView state on orientation change.

B4X:
Dim ScaleRect As Rect
ScaleRect = TouchImageView1.GetScaleRect

SetScaleRect (Rect as android.graphics.Rect, String as ScaleToFit)

Scale and position the image to the area of the TouchImageView defined by ScaleRect.
ScaleToFit controls how the image should be aligned in the Rect:

"CENTER" - Center and maximise the image to fit the Rect maintaining the aspect ratio.
"END" - Maximise the image to fit the Rect maintaining the aspect ratio, align the image with the bottom and right edges of the Rect.
"FILL" - Maximise the image to completely fill the Rect, the aspect ratio may not be maintained.
"START" - Maximise the image to fit the Rect maintaining the aspect ratio, align the image with the top and left edges of the Rect.

Note that if as a result of fitting the image to the Rect, the image has been scaled less than the current MinScale value then MinScale will be set to the current scale.
Likewise if when fitting the image to the Rect, the image has been scaled more than the current MaxScale value then MaxScale will be set to the current scale.

Documentation for the B4A Rect can be found here: Basic4android - Drawing (Core)
Documentation for Android ScaleToFit can be found here: Matrix.ScaleToFit

Example to position and scale the image so that it centers within a rectangle Left 20dip, Top 30dip, Right 100dip, Bottom 120dip, maximised but maintains it's aspect ratio:

B4X:
Dim ScaleRect As Rect
ScaleRect.Initialize(20dip, 30dip, 100dip, 120dip)
TouchImageView1.SetScaleRect(ScaleRect, "CENTER")

TouchEnabled as Boolean

Get or set whether touch events are currently enabled in the TouchImageView.

If touch events are enabled then the TouchImageView will NOT generate the standard ImageView Click and LongClick events.
These standard ImageView events will however be generated if touch events are NOT enabled.

TranslatePadding As Int

Get or set the minimum number of pixels that the image will always display within the TouchImageView.
Default TranslatePadding is 10 pixels - the image can not be dragged out of visibility, at least 10 pixels of width and/or height will always be visible.

B4X:
TouchImageView1.TranslatePadding = 50

I couldn't decide whether to implement setter and getter methods for the translate position and zoom scale - methods that would enable you to programmatically pan and zoom the image.
If anyone wants such methods then make a post in this thread and i'll see what i can do.


All other methods and properties of TouchImageView are inherited from the standard ImageView.
Documentation for the standard ImageView can be found here: Basic4android - Views (Core)

The attached demo shows basic usage and how to save and restore the TouchImageView state on orientation change.

TouchImageView updated to version 2.00, version 2.00 is not compatible with previous versions.
Methods and properties have changed.
Click here to read more


Martin.
 

Attachments

  • TouchImageView_v1_1.zip
    177.8 KB · Views: 2,270
  • TouchImageView_v_2_00.zip
    200.9 KB · Views: 4,665
Last edited:

PharCyDeD

Active Member
Licensed User
Longtime User
Very nice! Is there any way to only move the imageview when it is touched? Currently, you can touch wherever on the screen and it will start moving which is great, but I want it to feel like you are truly moving the object around with your finger.
 

warwound

Expert
Licensed User
Longtime User
Very nice! Is there any way to only move the imageview when it is touched? Currently, you can touch wherever on the screen and it will start moving which is great, but I want it to feel like you are truly moving the object around with your finger.

I have now updated the touch detection as requested.

Version 1.1 of TouchImageView is attached to the first post in this thread.

This library is great. Is it possible to rotate the image?

All things are possible as they say!
Such an update is far from straightforward though.

I shall do some research and brush up on my trigonometry and see what i can do next weekend.
This weekend is half over and i have work to do during the week.

Martin.
 

splatt

Active Member
Licensed User
Longtime User
Respect Martin.

Works superbly!

Would it be possible to add a double tap option to zoom to fit the screen?
 

warwound

Expert
Licensed User
Longtime User
Would it be possible to add a double tap option to zoom to fit the screen?

Ok i have added code to detect a double tap.
Also code to enable and disable the double tap and even set the period in milliseconds between taps that should be treated as a double tap.

Now to decide what action to take on a double tap?
I have written code which can do:

1) Center and fit the image to the TouchImageView maintaining aspect ratio.

OR

2) Restore the scale and position set when SetScaleRect was last executed.
If SetScaleRect has not been executed a double tap would set the image position at (0, 0) 100% size.

Maybe i should create a new method such as SaveCurrentState which would save the current image scale and position.
A double tap would restore that saved state - no need to add code for 1 and 2 above.

So after loading an image and setting the ScaleRect your code could call SaveCurrentState and you would have control over what a double tap does?

I could create a method RestoreSavedState so you could programmatically do what a double tap does...


What do you think?

I think instead of hardcoding the double tap action it'd be better to create those two new methods and leave the developer in control of the double tap action.

Martin.
 

Omar

Member
Licensed User
Longtime User
Martin,

Thanks for your efforts and sharing this with all of us. I think your suggestion to leave both options available for the double tap is the best option.

Thanks again.
 

warwound

Expert
Licensed User
Longtime User
I've been thinking about the doubletap action a bit more and think the most elegant solution would be for TouchImageView to generate a Double_Tap event.

I could add a few useful helper methods too and that should leave the developer in total control of the double tap action.

Martin.
 

splatt

Active Member
Licensed User
Longtime User
I've been thinking about the doubletap action a bit more and think the most elegant solution would be for TouchImageView to generate a Double_Tap event.

I could add a few useful helper methods too and that should leave the developer in total control of the double tap action.

Martin.

I would agree with your thinking Martin. It really works well. Thanks for your work.
 

PharCyDeD

Active Member
Licensed User
Longtime User
I am trying to get this to where it cannot be resized at all. If I make the max and min scale value the same...I can still resize it? :confused:
 

warwound

Expert
Licensed User
Longtime User
I am trying to get this to where it cannot be resized at all. If I make the max and min scale value the same...I can still resize it? :confused:

Try running the CreateLog method and look at the ScaleX and ScaleY values when you zoom the image - they're greater or lesser than the MaxScale and MinScale values you have set are they?

Are you also setting the ScaleRect?

If so then the answer is that when ScaleRect has scaled and positioned the image, it checks to see if in the process of scaling the image that the image current scale is greater than or less than MaxScale and MinScale.

If the scaling process has scaled the image more than MaxScale then MaxScale is set to the current scale.
Similarly if the scaling has scaled the image to less than MinScale then MinScale is set to the current scale.

If ScaleRect didn't do that then as soon as the image was touch it'd scale to MinScale or MaxScale.

Does that makes sense?

Basically it sounds as though you want to display the image with a scale of 'z'.
'z' is either less than MinScale or more than MaxScale.

I'm working on the DoubleClick event and some other new methods at the moment so will give this some thought and hopefully come up with a logical solution.

Martin.
 

PharCyDeD

Active Member
Licensed User
Longtime User
I left ScaleRect alone and only messed with the min and max scale values. What I am looking to accomplish is have the ImageView stay the same size as the original ImageView I place in my app via the designer. So if I add an ImageView with the width and height of 100 it can be moved around as needed, but not scaled in size at all. I am wanting to use this for an upcoming card game in development, but it would be odd for them to resize their cards lol. I am sure you are quite busy, but any help with this when you get the chance would be appreciated :)
 

warwound

Expert
Licensed User
Longtime User
I left ScaleRect alone and only messed with the min and max scale values. What I am looking to accomplish is have the ImageView stay the same size as the original ImageView I place in my app via the designer. So if I add an ImageView with the width and height of 100 it can be moved around as needed, but not scaled in size at all. I am wanting to use this for an upcoming card game in development, but it would be odd for them to resize their cards lol. I am sure you are quite busy, but any help with this when you get the chance would be appreciated :)

I have done some tests using this code:

B4X:
'Activity module
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.

End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
   Dim TouchImageView1 As TouchImageView
End Sub

Sub Activity_Create(FirstTime As Boolean)
   TouchImageView1.Initialize("")
   Activity.AddView(TouchImageView1, 0, 0, 100%x, 100%y)
   Activity.AddMenuItem("Create log", "CreateLog")
   
   TouchImageView1.MinScale=1
   TouchImageView1.MaxScale=1
   
   TouchImageView1.Bitmap=LoadBitmap(File.DirAssets, "cromer_pier.jpg")
   
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

Sub CreateLog_Click
   TouchImageView1.CreateLog
End Sub

As expected it loads the image, the image is draggable but not zoomable.

If i set MinScale and MaxScale to:

B4X:
TouchImageView1.MinScale=0.5
TouchImageView1.MaxScale=0.5

or

B4X:
TouchImageView1.MinScale=1.5
TouchImageView1.MaxScale=1.5

Then the activity starts and displays the image normal size (scale is 1), but as soon as i try a pinch zoom the image instantly scales itself to 0.5 or 1.5 and remains fixed at that scale.

Is that the behavior that you are seeing?

Martin.
 

PharCyDeD

Active Member
Licensed User
Longtime User
Perfect!! Yes, I am seeing the same results. It moves, but will not be resized and if I set to .5 or any other scale it automatically resizes to that value on touch. Now the only problem I am having is adding more imageviews. When I add an imageview via the designer I can't add: .TouchEnabled .CreateLog without the compiler telling me it is an unknown member (it doesn't pop up in the list to add at the end of imageviews either). I am adding this directly to your project for testing purposes but not getting the options I need. The library is installed and checked so I am not sure what is going on.
 
Top