I am trying to write code for zoom in/out the whole page/screen of the app. I was given this link
Android - zoom in/out RelativeLayout with spread/pinch
but
First, lets start simple. Scaling is relatively easy. (this code is not used in the further examples):
TextView rootView;
rootView.setScaleX(sx);
rootView.setScaleY(sx);
sx
and sy
is scale[X/Y]
That is the fundamentals of scaling. Now we go to the hard part: Pinch zoom. this requires user input in the form of touch events.
Start by setting an onTouchListener if you cannot use onTouchEvent for the root view. (I will not show this part)
Before you even start, declare a float called scaleFactor:
[ANY-ACCESS-MODIFIER] long scaleFactor = 1f;
First, we need a ScaleGestureListener. This can be a nested class if wanted:
class Scaler extends ScaleGestureDetector {
public Scaler(Context context, OnScaleGestureListener listener) {
super(context, listener);
}
@Override
public float getScaleFactor() {//Leave this method empty.
return super.getScaleFactor();
}
}
Secondly we need the OnScaleGestureListener:
class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener{
@Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
if(scaleFactor > 2) scaleFactor = 2;//Limit to your liking
else if(scaleFactor < 0.3f) scaleFactor = 0.3f;//Limit to your liking
scaleFactor = (scaleFactor * 100) / 100;//jitter-protection
//scaleMatrix.setScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());//This is for usage with a Matrix: Good for canvas and other areas where this is usable. This is from my own scaling code, so I keep the matrix around in this example in case it is needed
tv.setScaleX(scaleFactor);
tv.setScaleY(scaleFactor);
tv.setPivotX(detector.getFocusX());
tv.setPivotY(detector.getFocusY());
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {return true;}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {}
}
Now, this is where it splits in two. If possible, use onTouchEvent(MotionEvent ev)
. If you cannot use this method(when you add @Override
above it it shows an error) you have to use onTouchListener instead. set it on the TextView(tv.setOnTouchListener(this);
. Make sure the class implements OnTouchListener)
Now, whatever method you picked, MAKE SURE IT RETURNS true
!
This code should work in both methods, and it isn't limited to a specific method:
(ev is MotionEvent)
int pointers = ev.getPointerCount();
if(pointers == 2) {
zoom = true;
s.onTouchEvent(ev);//pass original motionevent(unscaled) to zoom
}
Now, the base code is in place. Now we need to create the instance for s
:
Globally declare:
private Scaler s;
private ScaleListener listener;
and where you inflate the layout:
listener = new ScaleListener();
s = new Scaler(c, listener);//c is a context.
Now, assuming all the components are in place you have a functioning zoom-in/out system. Please note that this does not cover scrolling on the zoomed view. You have to create an offsetX/Y variable, and take input when there is one pointer and check how far a distance you want to move.
Using a TextView and touch events, you can use #setScrollX or #setScrollY along with an offset to set the new, scrolled position.
It may though be easier to create your own, custom text view. You do this by creating a new class and making it extend TextView. Then you put modifications as you want into there. This would allow you to add zoom and such into the custom TextView. This is though a prefered way to do it if you have multiple textviews in a single class or you have multiple activities with a zoomable and scrollable textview.
EDIT: Custom textview
Sadly, not a lot of the integrated tools does nto work. android:scrollbars
on a textview doesn't work for an instance. So first the TextView has to have a ScrolLView around it:
<ScrollView android:id="@+id/textScroll"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.package.ZoomableTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some hfndusijhgn hgnm hnixjkgbhn fvb uynfv bunfg vbuygn buy hgnyu gnui h uh nuioiogfej uhud\nfhbnikjhgnuieskhg nmuimjhbnguijhgne \nfuyh ghfuisdghbuisjhgnuie dgjh\nifgb dsauingfbehja kbfiuej ksghbisdjkg nbhni\ngfdfjgdfh hdfh sdfhg sh "/>
</ScrollView>
And ZoomableTextView:
You need this dependency first:
compile 'com.android.support:appcompat-v7:25.3.1'
This is to get the AppCompat library so the TextView can use new features while maintaining support for earlier versions. now for the class:
public class ZoomableTextView extends AppCompatTextView/*This is why the AppCompat dependency is needed*/ {
private float textSize,
textScale;
private Scaler s;
private ScaleListener listener;
public ZoomableTextView(Context context) {
super(context);
init();
}
public ZoomableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ZoomableTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void init(){
listener = new ScaleListener();
s = new Scaler(getContext(), listener);
textSize = getTextSize();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
if(ev.getPointerCount() == 2){
s.onTouchEvent(ev);
}
return true;
}
class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener{
@Override
public boolean onScale(ScaleGestureDetector detector) {
textScale *= detector.getScaleFactor();
if(textScale > 2) textScale = 2;//Limit to your liking
else if(textScale < 0.3f) textScale = 0.3f;//Limit to your liking
textScale = (textScale * 100) / 100;//jitter-protection
if(textScale < 0.3f) textScale = 0.3f;
if(textScale > 2) textScale = 2;
setTextSize(textSize * textScale);
setPivotX(detector.getFocusX());
setPivotY(detector.getFocusY());
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {return true;}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {}
}
class Scaler extends ScaleGestureDetector {
public Scaler(Context context, OnScaleGestureListener listener) {
super(context, listener);
}
@Override
public float getScaleFactor() {//Leave this method empty.
return super.getScaleFactor();
}
}
}