This is feature rich fully extensible gesture library for Android.
NOTE: HacerGestoV3 has landed https://bitbucket.org/warwick/hacergestov3
Features of Library HacerGesto
All gestures can be dynamically enabled/disabled.
HacerGesto is fully extensible.
All of the gesture classes can be used independently outside the package in a project that does not contain the library. They only rely on the HGResult class. This is very handy to keep your deployment footprint to a minimum. They can also be used together outside of the library package by using the get/setMatrixValue methods. (though this method has not been fully tested).
All gestures work relative to padding. This is useful if you want to obscure a part of an image to simulate a view port.
The animated ImageView need not be in it's own layout, this was by design to make it easier for creating virtual view ports by manipulating the padding and/or margins of the parent view. It also serves for optimisation.
All gestures have a convenience method that expands the padding to the edges of the parent layout or shrinks it to zero.
All gestures have a method to return the matrix values.
The Rotate gesture! This gesture has: A snap to centre method for use when rotate and move is active. It has a method called 'setDialMode' which when set to true, turns it into a single finger gesture. Handy for small screens with a lot of controls. Rotate also now comes with a method called 'setAngleSnap' which causes the angle to snap a certain amount of degrees (1st parameter) for every amount the gesture rotates (second parameter). This gesture class has several public methods: 'double getAngleFromPoint(Point firstPoint, Point secondPoint)', 'getRotatedOrScaledSize(ImageView imageView)' which returns the size of the box that the rotated image would fit within. For your convenience the method also has a 'manualRotate(float angle, Point rotationCenterPoint)' method and a 'getRotatedBitmap(ImageView imageView)' method that reruns a new bitmap in it's current state.
The Scale gesture! This gesture now comes with a new snapping method 'setMinMaxSnap(float, float, float)'. The first two parameters of this method set a maximum and minimum scale size in pixels and the last is the amount of pixels to snap by. Setting the last parameter to zero will only enforce minimum/maximum size (without snapping). Setting the first two to zero will snap without checking the min/max bounds. This gesture also has a snap to centre function for when used in conjunction with the move gesture. By default this gesture will scale from the centre of it's current position. It also has a convenience method 'getProportionalBitmap(Bitmap bitmap, int newDimensionXorY, String XorY)' this method returns a proportionally scaled bitmap. When the last parameter is set to "X" it treats the newDimentionXorY as a new width and when set to "Y" a new height. Additionally it has a 'manualScale(float scaleX, float scaleY)' method and a method 'float getScaledSize()' method to return the XY size of of the image and a 'int getRotatedOrScaledSize(ImageView imageView)' method that does the same for when the image has been rotated. Of course the 'getProportionalBitmap' method can be used to return a scaled image in it's current state.
The move gesture! This gesture now has a new method added: 'setMoveSnap(Point snapPositions, float snapTolerances)' This method causes the move gesture to snap to a number of positions (1st parameter) when it comes within a certain proximity (2nd parameter) of a position. Each position can have a different snap tolerance. It also has a 'setCumaulativeMove' method. When set to false the movement will occur from where the finger is put down. When set to true the motion will occur relative to the touch. There is also a 'manualMove(float xPos, float yPos)' method.
The Fling Gesture! This gesture has two feature methods that make is extremely flexible and developer friendly. Though the default behaviour is to fling just off the edge of the screen, it is possible to capture the values in the onRelease (calling from onRelease is optional) and manipulate what the gesture will do. The method 'triggerFling(float dynamicFlingDistance, float width, float height)' will cause the gesture to fling a certain distance in pixels in the direction dictated by the second two parameters as a ratio relative to the upper-left of the animated image. When the first parameter is set to zero it will fling to the absolute position of the second two parameters. This method is greatly enhanced by a function contained in the 'HGResult' class which measures the diagonal distance between any two points. This method is 'getTwoFingerDistance(float firstTouchX, float firstTouchY, float secondTouchX, float secondTouchY)'. This gesture also comes with a 'setFlingDistance' method which will simply cause the fling to move a set distance in the direction of the gesture. Finally it has a 'setFlingBounceBack' which causes the gesture to move back to it's original position. The bounce back was just added to make testing a bit easier. There is some remarked out code in the library to suggest how the triggerFling method can be used.
Notice: HGDialV2 has landed check it out: https://bitbucket.org/warwick/hg_dial_v2
- Enhancements include: The way one dial acts upon another (acting dials) is greatly improved, optimised and very intuitive to the developer.
- The angle snap now functions intuitively with any angle snap angle (the angle no longer has to be evenly divisible by 1).
- Overall major optimisations.
- Better separation of concerns.
- Minimised lines of code.
- Added new usages (Can now add arrays of dial objects).
- Added save/restore and flush state objects.
- Can now interact with multiple dials at the same time.
- Works fluidly with device rotation.
At present I have 4 other useful libraries here that may be of interest to you:
Version 2 of this library (Powered by OpenGLES 2.0) https://bitbucket.org/warwick/hacergestov2
Dial Widget (Powered by Canvas and Extended Views) https://bitbucket.org/warwick/hgdialrepo
Open GLES2 Version 2 of my Dial Widget https://bitbucket.org/warwick/hggldial
HGDialV2 is currently in development. Once completed the developer will continue development HacerGestoV3. The architecture of HacerGestoV3 will be based on HGDialV2. HGDialV2 will have improvements on how one dial acts upon each other as this was very poor and un-intuitive in HGDial V1. HGDial V1 will remain available after V2 is complete. The developer may be further optimisations for HGDial V1 depending on what happens with HGDial V2.
When I get time I will be extending this library with extra functionality and I will be taking feature requests from the public. If you would like to use my library, but need some functionality that it does not yet implement, you may request such an addendum by emailing me at email@example.com. If I believe that the new functionality would be very useful to the public, I will add it in my spare time. alternatively, if you wish to donate modifications to this library, just submit them to me for approval and I will update the library and add your name as a contributor; if you so wish.
This library is designed to be extensible and have further gestures added, and for the gestures to have behavioral methods added. There are three things to take into consideration when extending this library which are related to the way that the gestures are designed to work together. Every gesture can effect one of 9 factors in the Matrix Values.
When the onDown occurs for each gesture, they in-turn set the Matrix values of the next gesture that is about to be called. The strategy I have employed is: The gesture that modifies the most Matrix factors (ie Trans, Scale, and Skew) are called first and the one that modifies the least is set last. You can observe this strategy by looking at the 'MotionEvent.ACTION_DOWN' section of the main 'HacerGesto' class. In this library Rotate is called first because it sets all three Matrix factors. This passes the Matrix values onto the Scale which effects the Scale and Move factors, and the Scale sets the Move gesture which only sets one Matrix factor.
Another strategy employed to get the gestures to play together is that all of the single finger gestures cancel them selves when a second finger goes down and all of the two finger gestures cancel themselves when the second finger goes up.
None of the on down events move the animation. This is to make it easier to capture values in the onDown override so that the client developer can manipulate the image between the onDown and onRelease. At present only the Fling gesture has been extended for such manipulation.
All single finger gestures cancel themselves when a second finger goes down this is the same for the Rotate gesture when dialMode is set to true. Though these gestures cancel themselves the touch is still reflected in the HGResult. All two finger gestures cancel themselves when the second finger goes up; meaning both fingers would need to be released to rework the gesture.
(Note most anomalies have a work around by dynamically enabling/disabling gestures, or using the manual methods) Scale and Rotate: When Scale and Rotate are both in snap to centre mode; the cantering will be thrown out. This doesn't seem to be the case when only rotate snap to centre is set to true. This is not a problem because using only using these two gestures with move, would make cantering both obsolete. Also the angle reflected in the HGResult object will be knocked out when using these two gestures together. This doesn't affect the animation itself.
When using Move/Rotate: If cumulative move is set to false the image will move slightly off centre of the touch. If Rotate is set to Dial mode the move will become disabled. This is not a problem as when in dial mode they are both single finger gestures.
When using Move/Scale: If snap to centre is enabled and cumulative move is disabled the image will drag off centre. The distance off centre will increase when scaling up.
Rotate: If you rotate with angle snapping set to false and then rotate with it set to true the value in the HGResult object will only return the degrees rotated and not the degrees rotated plus the last degrees. This will not be fixed because, fixed or unfixed; the developer will still be able to get a handle of the difference either way.
The source code contains all the information you will need in the comments of the 'MainFragment.java' file. Along with commented out code that can be un-commented. There is also a compiled demo application 'HacerGestoDemoRelease.apk'. Just install run and press the menu button. The rest is self explanatory.
This project is licensed with the 2-clause BSD license. The BSD 2-Clause License [OSI Approved License] The BSD 2-Clause License
In the original BSD license, both occurrences of the phrase "COPYRIGHT HOLDERS AND CONTRIBUTORS" in the disclaimer read "REGENTS AND CONTRIBUTORS".
Copyright (c) 2015, Warwick Weston Wright All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.