Pinch-Zoom Out does nothing, In makes screen disappear - android

I have to be missing something obvious, since everyone on the planet seems to be able to get the whole pinch-zoom thing to work. The main difference is most folks seem to be zooming on images, whereas I've a GridLayout (android-support-v7-gridlayout) with a bunch of text views. The goal seems simple enough: Allow the user to zoom in so that they can view a portion of the full grid at a larger size.
The grid draws fine, and horizontal & vertical scrolling work fine. And then, when I do a two-finger gesture with fingers moving apart (zoom), nothing happens, despite getting the log message that onScale has been called. When I move the two fingers in (pinch), all the views disappear (though my scroll bars are left).
I've looked at Matrix transformations but haven't seen that those work on anything but an image view.
The basic layout xml:
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<HorizontalScrollView
android:id="#+id/chooser_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</HorizontalScrollView>
</ScrollView>
Then in the activity
private ZoomGridLayout playerGrid;
and in onCreate:
ViewGroup gridParent = (ViewGroup) findViewById(R.id.chooser_layout);
playerGrid = new ZoomGridLayout(getBaseContext());
playerGrid.setRowCount(8);
playerGrid.setColumnCount(8);
LayoutParams layout =
new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
playerGrid.setDetector();
gridParent.addView(playerGrid, layout);
I then proceed to add ~150 small text views to the grid.
Here's the first take at ZoomGridLayout:
public class ZoomGridLayout extends GridLayout {
private final static String TAG = "ZGL";
private ScaleGestureDetector scaleDetector;
private Context context;
public void setDetector() {
scaleDetector = new ScaleGestureDetector(context, new ScaleGesture());
}
public ZoomGridLayout(Context c) {
super(c);
context = c;
}
#Override
public boolean onTouchEvent (MotionEvent event) {
scaleDetector.onTouchEvent(event);
return true;
}
private class ScaleGesture
extends ScaleGestureDetector.SimpleOnScaleGestureListener
{
#Override
public boolean onScale(ScaleGestureDetector detector) {
Log.v(TAG, detector.toString());
ScaleAnimation scale =
new ScaleAnimation(detector.getPreviousSpan(),
detector.getCurrentSpan(),
detector.getPreviousSpan(),
detector.getCurrentSpan());
scale.setFillAfter(true);
startAnimation(scale);
return true;
}
}
}
I've been beating my head against this for a couple days now. I'm new to Android programming, so not very familiar with the libraries, but I'm an experienced developer. Any pointers would be wonderful. TIA.

I gave up on animations (though eventually I'd like to try to make that work). Here's the new onScale method:
#Override
public boolean onScale(ScaleGestureDetector detector) {
Log.v(TAG, detector.toString());
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(MIN_SCALE, Math.min(mScaleFactor, MAX_SCALE));
invalidate();
return true;
}
this is then complemented by overriding the draw method:
#Override
public void dispatchDraw(Canvas canvas) {
String disp = String.valueOf(mScaleFactor);
Log.v(TAG, "dispatch draw " + disp);
canvas.save();
canvas.scale(mScaleFactor, mScaleFactor);
super.dispatchDraw(canvas);
canvas.restore();
}
i also learned that since the parent is a ViewGroup instead of a View, that one needs to override the dispatch… methods instead of the on… methods.
there are so many different variants of this pattern out there. i hope this particular wrinkle helps someone else.

Related

Creating zoom functionality in android drawable that lies inside image-view

I am trying to follow the tutorial from https://www.youtube.com/watch?v=X2ls3FTPOAc in order to zoom into my drawable which lies inside an imageview.
I see here that the scaleListener object is called since the Log outputs that it's being called. However, when I use the ImageView.ScaleType.MATRIX scale type for the image-view it doesn't seem to work. I've also added a slight modification in the onScale method. Here's my code:
view1.setScaleType(ImageView.ScaleType.MATRIX); //using CENTER works
Matrix matrix = new Matrix();
view1.setImageMatrix(matrix);
DummyDraw drawD = new DummyDraw(this);
view1.setImageDrawable(drawD);
scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
a few methods down I have:
public boolean onTouchEvent(MotionEvent event){
scaleGestureDetector.onTouchEvent(event);
return true; }
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener{
public boolean onScale(ScaleGestureDetector detector) {
Log.d("inside1044","inside scale listener onSscale method ");
float scaleFactor = detector.getScaleFactor();
scaleFactor = Math.max(0.1f, Math.min(scaleFactor,5.0f));
scaleFactor2 = scaleFactor;//a modification I made
matrix.setScale(scaleFactor,scaleFactor);
view1.invalidateDrawable(view1.getDrawable());//this is the modification I made
return true;}
}
Now, the DummyDraw class extends Drawable which just draws a pink background and a circle in the middle of the canvas. the variable scaleFactor2 is static and defined in the MainActivity, so everytime the user touches the view the method onScale is called updating the new value for scaleFactor2. I use this scaleFactor2 value somehow to try to scale the canvas of my drawable object. Here's what the code looks like inside the drawable object, inside the onDraw():
//define some variables to get the center of the canvas
canvas.save();
canvas.scale(MainActivity.scaleFactor2,MainActivity.scaleFactor2);
//draw the circle to the screen
canvas.restore();
When I place both fingers on the screen and bring them closer together the circle jumps and moves slightly, however when I move the fingers apart nothing happens. Remember, that this works only when the ImageView.ScaleType is set to CENTER not to MATRIX.
I am trying to accomplish a smooth zoom in and out of the view.
Any ideas would be appreciated.

Pinch Zoom and 2 finger Rotation the ImageView in Android

I've a problem from last 2 days and unable to tackle it as I'm newbie. Actually I'm working on an Android App that needs pinch-zoom and 2-finger rotation on Android ImageView. I got the multiple tutorials and solutions that work fine for Pinch Zoom and but does not work for 2 finger rotation. I'm sharing the simplest tutorial that's easy to understand and I want to extend it for 2 finger rotation. Here is the code snippet:
public class MainActivity extends Activity {
private ImageView mImageView;
private Matrix mMatrix = new Matrix();
private float mScale = 1f;
private ScaleGestureDetector mScaleGestureDetector;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.imageView);
mScaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
}
public boolean onTouchEvent(MotionEvent ev) {
mScaleGestureDetector.onTouchEvent(ev);
return true;
}
private class ScaleListener extends ScaleGestureDetector.
SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScale *= detector.getScaleFactor();
mScale = Math.max(0.1f, Math.min(mScale, 5.0f));
mMatrix.setScale(mScale, mScale);
mImageView.setImageMatrix(mMatrix);
return true;
}
}
}
Also I want to use them for GPUImage, I mean despite of Android ImageView I want to use GPUImage. How to transform the GPUImage to ImageView? This is the 2nd thing. First I want to implement the 2 finger rotation (or MultiTouch in some sense). Thanks
Here is the solution that worked good for me. https://stackoverflow.com/a/18276033 Only one line I should add here and that should be
add imageView.setRotation(imageView.getRotation() + (-angle)); in OnRotation(RotationGestureDetector rotationDetector) method inside the activity to set the new rotation value to the ImageView
This is for basic help. Remaining of the implementation is just fine
This is the library I created, which creates a imageview class can drag, rotate and zoom
Requirement: (Add on build.gradle)
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Add Dependency
dependencies {
implementation 'com.github.lau1944:Zoom-Drag-Rotate-ImageView:1.0.0'
}
first , add image on xml:
<com.easystudio.rotateimageview.RotateZoomImageView
android:id="#+id/rotate"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="#drawable/money"/>
or add programmatically:
RotateZoomImageView iv;
RelativeLayout playground = findViewById(R.id.playground);
iv = new RotateZoomImageView(getApplicationContext());
iv.setImageDrawable(getDrawable(R.drawable.money));
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(250, 250);
lp.addRule(RelativeLayout.BELOW);
iv.setLayoutParams(lp);
playground.addView(iv);
Step 2 : set up ontouchmethod
iv.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return iv.onTouch(v,event);
}
});
And that is it .

How to make a linear layout scrollable and zoomable in Android?

I have a LinearLayout in my Android app and I would like to make it scrollable in all directions. I simply implemented this with a HorizontalScrollView and ScrollView under which I placed my layout.
This works great, but I would like to implement pinch-zoom as well.
So I was inspired by this question: Android - zoom in/out RelativeLayout with spread/pinch
and I came up with the following layout:
<com.example.ZoomableScrollView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.2"
android:scrollbars="none"
android:background="#android:color/black">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout
android:id="#+id/sheet_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
</LinearLayout>
</HorizontalScrollView>
</com.example.ZoomableScrollView>
The children of the inner LinearLayout are dynamically added (they are simple TextViews inside horizontal LinearLayouts to make a simple table).
The ZoomableScrollView is quite simple and looks like this:
public class ZoomableScrollView extends ScrollView {
float mScaleFactor = 1.f;
private final ScaleGestureDetector mScaleDetector;
static final float MIN_SCALE = 1f;
static final float MAX_SCALE = 4f;
public ZoomableScrollView(Context context) {
this(context, null, 0);
}
public ZoomableScrollView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ZoomableScrollView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
mScaleDetector = new ScaleGestureDetector(context, new OnScaleListener());
}
#Override
public boolean onTouchEvent(MotionEvent event) {
Log.w("DEBUG", "On touch event");
boolean retVal = mScaleDetector.onTouchEvent(event);
return super.onTouchEvent(event) || retVal;
}
#Override
protected void dispatchDraw(Canvas canvas) {
Log.w("DEBUG", String.format("Scaling with scale factor %f", mScaleFactor));
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScaleFactor, mScaleFactor);
super.dispatchDraw(canvas);
canvas.restore();
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
private class OnScaleListener 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(MIN_SCALE, Math.min(mScaleFactor, MAX_SCALE));
Log.w("DEBUG", "OnScale: scale factor: " + mScaleFactor);
invalidate();
return true;
}
}
}
I have 2 issues with this:
The zooming is not very smooth, sometimes the View will scroll when it should zoom. That's not such a big deal atm.
When zooming, the LinearLayout becomes smaller and you can't scroll everywhere anymore. I think I understand why this is the case, but I don't know how to change that and I'm thinking that I went into the wrong direction here.
I don't mind changing the layout completely. In the end, I would like to have it behave a bit like a browser, where you can zoom and scroll everywhere (not as complex though). Is there a simple solution for this ?
As for two dimensional scrollView I had used this one. Maybe you should try to add pinch for it.

Make android layout and nested layouts within zoomable

I've been working on an app with complex layouts. I recently realized I need to make parts or all of my layouts zoomable.
One of my main xml files has a linear layout with multiple layouts nested within it to positions views properly. Is there an easy way to make this linear layout and everything within in zoomable? Or would it be easier to make the entire layout file zoomable? What are my options?
First of all extend that class with that specific view
public class MyImageView extends ImageView{
Override following method .
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.scale(mScaleFactor, mScaleFactor, midPoint.x, midPoint.y);
if(appInitialized) {
hsSide.draw(canvas);
scaleA.draw(canvas);
scaleB.draw(canvas);
}
canvas.restore();
}
Create a Gesture Detector that will detect size of zoomed object and you can limit to avoid overlaps.
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
pivotX = detector.getFocusX();
pivotY = detector.getFocusY();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.8f, Math.min(mScaleFactor, 2.0f));
invalidate();
return true;
}
}
At the end initialize the object
ScaleGestureDetector mScaleDetector;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
You might have a look at static transformations. Any ViewGroup or subclass can be customized to apply a transformation to its child views. You enable this by calling setStaticTransformationsEnabled(true), and then overriding the getChildStaticTransformation() callback (docs link) in your custom ViewGroup. You can apply any transformation you like, including a scale to create your zoom effect. This callback will be called any time the view needs to be redrawn or is invalidated.
Also, beware when using this alongside hardware acceleration. Depending on the frequency with which you need to update the transformations you may find hardware doesn't quite work to redraw as you expect. If so, you will need to enable software layers for this view hierarchy.

How to work with the X,Y Coordinates in android

I am new to android and I am trying with positioning my drawings at the right coordinate using touch screen. When i touch the screen I obtain the coordinates(x,y) but when i press my button to draw the circle it draws the circle at a location below the point i touched.I am using a relativeLyout as my layout, and i gave it an ID as "Layout" which I use to reference it in my java class.I thought it is because i am using the addView to draw on the same layout.I tried all my best to correct it but could not. (THE CIRCLE IS DRAWN AFTER CLICKING THE BUTTON BUT NOT AT THE POSITION I WANT IT, IT GOES BELOW THE POINT I TOUCHED)Can someone please help me.
Here is my code.
public class MyView extends View{
float x ;
float y ;
int radius = 20;
public MyView(Context context, float x, float y){
super(context);
this.x = x;
this.y = y;
} //end constructor
public void onDraw(Canvas canvas){
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
canvas.drawCircle(x, y, radius, paint);
} //end onDraw
} //end class MyView
Here is my MAIN CLASS:
public class ButtonClickActivity extends Activity implements OnClickListener{
RelativeLayout laying;
Button button;
MyView myView;
private static float x=100;
private static float y=100;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_button_click);
laying = (RelativeLayout) findViewById(R.id.layout);
button = (Button) findViewById(R.id.circle);
//set listeners
button.setOnClickListener(this);
} //end onCreate
public void onClick(View view){
switch(view.getId()){
case R.id.circle:
myView = new MyView(this, x, y);
laying.addView(myView);}
Here is the Touch event
public boolean onTouchEvent(MotionEvent event){
int action = event.getAction();
//get the type of action
switch(action){
case MotionEvent.ACTION_DOWN: //you have touch the screen
x = event.getX();
y = event.getY();
break
}
}
Here is the Layout
<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"
android:layout_gravity="center"
android:id="#+id/layout" >
<Button
android:id="#+id/circle"
android:layout_alignParentBottom="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight = "1"
android:text="Circle"/>
</RelativeLayout>
What you miss is the size of the view. Your custom view doesn't know how much space it needs for the circle, and the default one is wrap content, so what is the minimal size? That's right: 0.
That's why you can't see anything. Either you set a size from outside of the view, or you measure it somehow yourself within the view and tell the parent view what size the view needs (and then check what the parent gives you and use it).
Read here for more information about custom views.
Incidentally, it's not recommended to create the paint inside the onDraw, at least not in a way that recreates it each time it's called.

Categories

Resources