java - How to maintain the focus point in a Pan/Zoom Android Layout while zooming? -
i have custom layout extends framelayout , supports need. scrolling , zooming child view or layout works well. 1 thing having trouble maintaining focus point while zooming. center point between pinching fingers moves off screen, work google maps app focus(center) point maintained.
here's code.
public class betterzoomlayout extends framelayout { // state objects , values related gesture tracking. private scalegesturedetector mscalegesturedetector; private gesturedetectorcompat mgesturedetector; private static final float min_zoom = 1.0f; private static final float max_zoom = 4.0f; private float scale = 1.0f; private float lastscalefactor = 0f; // how translate canvas private float distancex = 0f; private float distancey = 0f; public betterzoomlayout(context context) { super(context); init(context); } public betterzoomlayout(context context, attributeset attrs) { super(context, attrs); init(context); } public betterzoomlayout(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); init(context); } private void init(context context) { // sets interactions mscalegesturedetector = new scalegesturedetector(context, mscalegesturelistener); mgesturedetector = new gesturedetectorcompat(context, mgesturelistener); } @override public boolean ontouchevent(motionevent event) { boolean retval = mscalegesturedetector.ontouchevent(event); retval = mgesturedetector.ontouchevent(event) || retval; applyscaleandtranslation(); return retval || super.ontouchevent(event); } /** * scale listener, used handling multi-finger scale gestures. */ private final scalegesturedetector.onscalegesturelistener mscalegesturelistener = new scalegesturedetector.simpleonscalegesturelistener() { /** * active focal point in terms of viewport. local * variable kept here minimize per-frame allocations. */ @override public boolean onscalebegin(scalegesturedetector scalegesturedetector) { lastscalefactor = 0f; return true; } @override public boolean onscale(scalegesturedetector scalegesturedetector) { float scalefactor = scalegesturedetector.getscalefactor(); if (lastscalefactor == 0 || (math.signum(scalefactor) == math.signum(lastscalefactor))) { scale *= scalefactor; scale = math.max(min_zoom, math.min(scale, max_zoom)); lastscalefactor = scalefactor; } else { lastscalefactor = 0; } return true; } }; /** * gesture listener, used handling simple gestures such double touches, scrolls, * , flings. */ private final gesturedetector.simpleongesturelistener mgesturelistener = new gesturedetector.simpleongesturelistener() { @override public boolean ondown(motionevent e) { return true; } @override public boolean onscroll(motionevent e1, motionevent e2, float dx, float dy) { setuptranslation(dx, dy); return true; } @override public boolean onfling(motionevent e1, motionevent e2, float velocityx, float velocityy) { //fling((int) -velocityx, (int) -velocityy); return true; } }; private void setuptranslation(float dx, float dy) { distancex = -1 * dx + distancex; distancey = -1 * dy + distancey; getparent().requestdisallowintercepttouchevent(true); rect viewablerect = new rect(); betterzoomlayout.this.getdrawingrect(viewablerect); float offscreenwidth = child().getwidth() - (viewablerect.right - viewablerect.left); float offscreenheight = child().getheight() - (viewablerect.bottom - viewablerect.top); float maxdx = (child().getwidth() - (child().getwidth() / scale)) / 2 * scale; float maxdy = (child().getheight() - (child().getheight() / scale)) / 2 * scale; distancex = math.min(math.max(distancex, -(maxdx + offscreenwidth)), maxdx); distancey = math.min(math.max(distancey, -(maxdy + offscreenheight)), maxdy); } private void applyscaleandtranslation() { child().setscalex(scale); child().setscaley(scale); child().settranslationx(distancex); child().settranslationy(distancey); } private view child() { return getchildat(0); } }
Comments
Post a Comment