Reputation: 6792
How to achieve this feature, PullToZoom only with an ImageView (Without the ListView in the sample)?
Similar question, but no answer :(
Upvotes: 4
Views: 2368
Reputation: 5773
What about using the Gesture Detector? You can find and implementation of what (I think) you need in the following code:
public class MainActivity extends AppCompatActivity {
private static final String DEBUG_TAG = "Gestures";
private GestureDetectorCompat mDetector;
private ImageView imageView;
private MyGestureListener myGestureListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView) findViewById(R.id.image);
myGestureListener = new MyGestureListener();
mDetector = new GestureDetectorCompat(this, myGestureListener);
imageView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
if (action == MotionEvent.ACTION_UP) {
myGestureListener.upDetected();
}
return mDetector.onTouchEvent(event);
}
});
imageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.test));
}
class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
private static final float MAX_ZOOM = 0.5f;
private static final float PCT = 300f;
private float delta;
private ValueAnimator valueAnimator;
@Override
public boolean onDown(MotionEvent event) {
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (valueAnimator != null) {
valueAnimator.cancel();
}
delta += distanceY;
float pct = getPct(delta);
imageView.setScaleX(1.0f + pct);
imageView.setScaleY(1.0f + pct);
return false;
}
void upDetected() {
float pct = getPct(delta);
valueAnimator = new ValueAnimator();
valueAnimator.setFloatValues(pct, 0.0f);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
imageView.setScaleX(1.0f + (float) animation.getAnimatedValue());
imageView.setScaleY(1.0f + (float) animation.getAnimatedValue());
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
delta = 0f;
imageView.setScaleX(1.0f);
imageView.setScaleY(1.0f);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
valueAnimator.start();
}
private float getPct(float delta) {
float pct = delta / PCT;
if (pct >= MAX_ZOOM) {
pct = MAX_ZOOM;
}
else if (pct <= -MAX_ZOOM) {
pct = -MAX_ZOOM;
}
return pct;
}
}
}
The MainActivity has a simple ImageView. When you 'scroll' inside it, the gesture is detected and the image is scaled (up or down). When you remove the finger from the screen, the image is scaled back to its original size with a simple animation. If you want to avoid the zoom out, you just need to work on getPct() method.
For example the getPtc could be something like this (if you are interested just to the zoom in)
private float getPct(float delta) {
float pct = -delta / PCT;
if (pct >= MAX_ZOOM) {
pct = MAX_ZOOM;
}
else if (pct <= 0) {
pct = 0;
}
return pct;
}
It seems that the very first scroll event of the gesture detector is wide. I've added some code to ignore it
class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
private static final float MAX_ZOOM = 0.8f;
private static final float PCT = 300f;
private float delta;
private ValueAnimator valueAnimator;
private boolean mFirstEvent = true;
@Override
public boolean onDown(MotionEvent event) {
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (valueAnimator != null) {
valueAnimator.cancel();
}
if (mFirstEvent) {
mFirstEvent = false;
return false;
}
delta += distanceY;
float pct = getPct(delta);
imageView.setScaleX(1.0f + pct);
imageView.setScaleY(1.0f + pct);
textView.setScaleY(1.0f - pct);
return false;
}
void upDetected() {
mFirstEvent = true;
float pct = getPct(delta);
valueAnimator = new ValueAnimator();
valueAnimator.setFloatValues(pct, 0.0f);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
imageView.setScaleX(1.0f + (Float) animation.getAnimatedValue());
imageView.setScaleY(1.0f + (Float) animation.getAnimatedValue());
textView.setScaleY(1.0f - (Float) animation.getAnimatedValue());
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
delta = 0f;
imageView.setScaleX(1.0f);
imageView.setScaleY(1.0f);
textView.setScaleY(1.0f);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
valueAnimator.start();
}
private float getPct(float delta) {
float pct = -delta / PCT;
if (pct >= MAX_ZOOM) {
pct = MAX_ZOOM;
}
else if (pct <= 0) {
pct = 0;
}
return pct;
}
/*private float getPct(float delta) {
float pct = delta / PCT;
if (pct >= MAX_ZOOM) {
pct = MAX_ZOOM;
}
else if (pct <= -MAX_ZOOM) {
pct = -MAX_ZOOM;
}
return pct;
}*/
}
Upvotes: 3