In my current project I need my users to be able to scroll over and zoom in on large SVG
Images. A major problem i encountered though, is the limit the android WebView class puts on zooming in and out. Is there any way I can remove or change these limits to my own likings?
The standard zoom controls do not seem to support releasing these boundries.
If my question is unclear, or if I need to elaborate on my question do not hesitate to ask.
Greets,
Wottah
Since no one seems to have come up with a different solution than using reflection - I'm not aware of any alternatives at this point - I wrote up a quick code snippet that illustrates how to bypass the upper limit on the zoom-in action.
Note that the code below will only work on ICS, and possibly Honeycomb, but I currently don't have a tablet lying around to inspect if the inner workings rely on the same ZoomManager class. Gingerbread, Froyo and Eclair all appear to implement the zooming functionality more or less directly in the WebView class. With the example below it should be fairly easy to add some code to also take those operating systems into account.
// just set an Activity's content view to a single WebView for this test
WebView mWebview = new WebView(this);
setContentView(mWebview);
// retrieve the ZoomManager from the WebView
Class<?> webViewClass = mWebview.getClass();
Field mZoomManagerField = webViewClass.getDeclaredField("mZoomManager");
mZoomManagerField.setAccessible(true);
Object mZoomManagerInstance = mZoomManagerField.get(mWebview);
// modify the "default max zoom scale" value, which controls the upper limit
// and set it to something very large; e.g. Float.MAX_VALUE
Class<?> zoomManagerClass = Class.forName("android.webkit.ZoomManager");
Field mDefaultMaxZoomScaleField = zoomManagerClass.getDeclaredField("mDefaultMaxZoomScale");
mDefaultMaxZoomScaleField.setAccessible(true);
mDefaultMaxZoomScaleField.set(mZoomManagerInstance, Float.MAX_VALUE);
Related
Currently, I am adding a list of annotations to a mapview with code similar to the following:
// Add to map view
SKAnnotation annotation = new SKAnnotation(i++);
annotation.getLocation().setLongitude(result.longitude);
annotation.getLocation().setLatitude(result.latitude);
annotation.setMininumZoomLevel(1);
annotation.setAnnotationType(SKAnnotation.SK_ANNOTATION_TYPE_PURPLE);
mapView.addAnnotation(annotation, SKAnimationSettings.ANIMATION_POP_OUT);
Yet whenever I view the annotations on the map, they disappear after I zoom out to anything under zoom level 4.0. Looking at the docs for the Annotation class (as well as confirming in the code), I see that the default zoom level is set to 4, yet it seems that my call to .setMinimumZoomLevel is ignored.
Does anyone have any insight into what is happening or if this might be a known bug within the SDK?
I'm using Skobbler 2.5 on Android.
Thanks for any help in the matter!
Based off Ando's comment on the original question and referencing the documentation here, I updated the code to use the workaround he described to allow annotations to show up down to zoom level 2.
Original code:
SKAnnotation annotation = new SKAnnotation(i++);
annotation.getLocation().setLongitude(result.longitude);
annotation.getLocation().setLatitude(result.latitude);
annotation.setMininumZoomLevel(1); // Note: this does not work
annotation.setAnnotationType(SKAnnotation.SK_ANNOTATION_TYPE_PURPLE);
mapView.addAnnotation(annotation, SKAnimationSettings.ANIMATION_POP_OUT);
Updated code:
SKAnnotation annotation = new SKAnnotation(i++);
annotation.getLocation().setLongitude(result.longitude);
annotation.getLocation().setLatitude(result.latitude);
annotation.setMininumZoomLevel(2);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
if (metrics.densityDpi < DisplayMetrics.DENSITY_HIGH) {
annotation.setImagePath(SKMaps.getInstance().getMapInitSettings().
getMapResourcesPath() + "/.Common/icon_greypin#2x.png");
// set the size of the image in pixel
annotation.setImageSize(128);
} else {
annotation.setImagePath(SKMaps.getInstance().getMapInitSettings().
getMapResourcesPath()+ "/.Common/icon_greypin#3x.png");
// set the size of the image in pixels
annotation.setImageSize(256);
}
mapView.addAnnotation(annotation, SKAnimationSettings.ANIMATION_POP_OUT);
A couple things to note:
.setImagePath() and .setImageSize() are both deprecated methods in the latest SDK even though they're still referenced in the documentation above. Not sure if that means there is another alternative to displaying images via an absolute path approach, or if they're simply phasing this functionality out.
In my particular example, we're using the purple pin to display annotations, but the absolute path file name for that pin is actually called icon_greypin. It looks like the other pin image file name are named appropriately however.
Anyways, this served as a solution for my particular problem until the SDK is updated, so I'm marking it as the answer and I hope it helps someone else! Thanks to Ando for the step in the right direction!
With Unity, the CardboardHead script is added to the main camera and that handles everything quite nicely, but I need to be able to "recenter" the view on demand and the only option I see so far is to rorate the entire scene and it seems like this is something the would address first-hand and I can't find anything in the docs.
With Oculus Mobile SDK (GearVR), it would be OVRCamera.ResetCameraPositionOrientation(Vector3.one, Vector3.zero, Vector3.up, Vector3.zero); though they handle it nicely each time the viewer is put on so it's rarely needed there.
There's a "target" parameter on the CardboardHead that lets you use to another gameobject as a reference for rotation. Or you can use a dummy parent gameobject. Either way, when you want to recenter, you set this reference object's rotation so that the CardboardHead is now pointing forward. Add this function to an script on the CardboardHead (or just add it into that script):
public void Recenter() {
Transform reference = target != null ? target : transform.parent;
if (reference != null) {
reference.rotation = Quaternion.Inverse(transform.rotation) * reference.rotation;
// next line is optional -- try it with and without
reference.rotation = Quaternion.FromToRotation(reference.up, Vector3.up) * reference.rotation;
}
}
Cardboard.SDK.Recenter (); should do the trick.
Recenter orientation Added Recenter() function to Cardboard.SDK, which resets the head tracker so the phone's current heading becomes the forward direction (+Z axis).
Couldn't find the docs for the API/SDK but it's in the release notes for the v0.4.5 Update.
You can rotate the Cardboard Main to point in a certain direction.
This is what worked for me when I wanted the app to start up pointing a certain way. Since the CardboardHead points at Vector3.zero on startup if no target is assigned, I ran a function during Start() for the CardboardMain that would point in the direction I wanted.
Of course, if you're already rotating CardboardMain for some other reason, it may be possible to use this same method by creating a parent of the CardboardHead (child of CardboardMain) and doing the same thing.
This question is a bit old but for Google VR SDK 1.50+ you can do
transform.eulerAngles = new Vector3(newRot.x, newRot.y, newRot.z);
UnityEngine.VR.InputTracking.Recenter();
also, if you don't want to get confused you also need to catch the GvrEditorEmulator instance and Recenter it as well.
#if UNITY_EDITOR
gvrEditorEmulator.Recenter();
#endif
Recentering GvrEditorEmulator though doesn't seem to work very well at the moment but if you disable it you'll see the recentering works for the main camera.
I've been trying to sort out an issue for a week or so now. Googled to no avail. I'm currently working on an iOS/Android app that has a feature in the game to take a screenshot and have it show up in the mobile device's gallery.
I'm using the CameraRoll object and the issue is that some objects on screen have smoothing applied. However the CameraRoll screenshot ignores this. Which makes the resulting screen shot have some objects with jaggies.
I've found a number of cries for help on the same issue while googling, but no answers.
Any help is much appreciated.
Jaggies in flash are common since smoothing on bitmaps is disabled by default (more cpu intensive). I'd recommend creating a new bitmap from the CameraRoll MediaEvent.SELECT event. Inside, it should return event.data which is a MediaPromise object. Inside that, you should find a read-only file property where you should be able to find the image.
Then it's just a matter of creating your new image with smoothing.
var img:Bitmap = new Bitmap();
img.bitmapData = file.bitmapData;
img.smoothing = true;
addChild(img);
I've never tried this on mobile before, but it's a common issue which I believe you're encountering.
Addendum:
If you're having an issue with the system based screenshot services, you could create your own using pure AS3. The logic being, AS3 should do a pixel-by-pixel block copy of the stage (thereby respecting the smoothing values of your images).
Try this:
var myBitmapData:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight);
myBitmapData.draw(stage);
This question already has answers here:
Android WebView renders blank/white, view doesn't update on css changes or HTML changes, animations are choppy
(9 answers)
Closed 9 years ago.
I am developing an open-source browser called Lightning Browser, and I have run into some trouble with the most recent update to Android (4.2.2).
WebViews will fail to render completely until the view is touched. It only occurs on the latest Android version. On 4.2.1, the WebView rendered completely fine. I use my Nexus 7 for development and right after I received the 4.2.2 update, the browser stopped rendering. Other users experienced this as well, and it was confirmed multiple times to happen ONLY on 4.2.2. It is happening targeting API level 16 and 17, but I have seen a WebKit browser that targets API level 9 without this problem.
I have attempted to remedy this using the solution to a problem I found here on Stack Overflow (Android WebView renders blank/white, view doesn't update on css changes or HTML changes, animations are choppy). HOWEVER, setting the WebView's RenderPriority to high alone does not solve it... the only way to get it to render without being touched was to place the invalidate() command inside the OnDraw() method of WebView. This causes the WebView to re-draw continuously. This works (sort of), animations are smooth, the page loads very quickly, but it causes the WebView's performance to drop otherwise.
I have also seen this question (very similar to mine), but there is no good answer for it. Android WebView Fails to Completely Render Content Until User Interaction
By performance drop, I mean input. Text input lags, and the WebView itself cannot handle what is going on as well as before. Benchmarking the browser with the invalidate() method call drops Benchmarking performance by around 8%. I know benchmarks aren't everything, but it's telling me that the continuous drawing is straining the system and causing the system to ignore other tasks.
In Conclusion...
The WebView in Android 4.2.2 will not render until touched. The only way I know to fix this is to call invalidate() in the onDraw() method of WebView. This is bad for performance and I am looking for a different way to fix this.
The Magic Code (I'm currently using)...
class MyWebView extends WebView
{
#Override
onDraw(Canvas canvas)
{
invalidate();
super.OnDraw(canvas);
}
}
remove
invalidate();
and it doesn't render until touched.
Does anyone have a suggestions on how make the WebView render (other than what I've done)? By the way, this is my first question I've asked here on Stack, so forgive me if I haven't been clear or if I've done something wrong.
EDIT:
I found this question here about a similar issue and it was resolved, the problem is, I don't understand what the answer even means. If anyone could enlighten me it might help.
I get this error in logcat
E/chromium(1243): external/chromium/net/disk_cache/backend_impl.cc:2022: [0705/172030:ERROR:backend_impl.cc(2022)] Corrupt Index file
So I finally found the issue causing the WebView not to render. I am starting and stopping the animation of a drawable inside the WebViewClient of my WebView. This drawable is simply a refresh button that rotates when the page is loading... simple right?
Well in the non-fullscreen mode of the browser, the rotating drawable and the WebView are both children of the same parent, whereas in the fullscreen mode, the drawable becomes a child of the WebView. Somehow, by starting the animation when the page is loading and stopping it when it's done (in fullscreen), the application decides that the rotating drawable is what needs all the drawing power and the WebView never draws. When in fullscreen mode and the drawable becomes a child of the WebView, the WebView then has a higher rendering priority than the drawable and it draws fine.
The moral of the story is... WebViews like to be the highest priority view to be drawn. If there are other views that get greater priority, they won't draw correctly.
I'm no expert on animations, so I need to rethink how I'm animating the drawable now so as to not interrupt the WebView.
Hopefully that made sense. Thanks for reading.
Disable hardware acceleration on your manifest:
android:hardwareAccelerated="false"
please see the last answer by #Olivier on Android WebView renders blank/white, view doesn't update on css changes or HTML changes, animations are choppy , he triggers a couple delayed invalidates on WebView's OnTouchEvent rather than continuosly on onDraw ... In my case it worked because (most) of my problems were after a user touching webview and I changing some CSS in response. Of course it doesn't apply at all on the case of automatic / timeout'ed css
In my case it also helped to export a JavaScript function from Java to manually trigger invalidate with a delay, so if in JavaScript you more or less know where the disaster might happen you can manually trigger it, something like this inner class inside your WebView:
public class MyWebView extends WebView {
private class InvalidateExtension {
private Handler handler=new Handler(); // you might already have a handler
private Runnable mInvalidater=new Runnable() {
#Override
public void run() {
MyWebView.this.invalidate();
}
}
public void trigger(int delay) {
handler.postDelayed(mInvalidater, delay);
handler.postDelayed(mInvalidater, 2*delay); // just in case
handler.postDelayed(mInvalidater, 4*delay); // just in case just in case :)
}
}
/** Call this function on this view's init, BEFORE loading a page so it is available to JS */
private void call_me_on_init_to_enable_hack() {
addJavascriptInterface(new InvalidateExtension(), "Invalidater");
}
}
So, from JavaScript you can do:
Invalidater.trigger(100);
And play with the milliseconds value ....
Hope this helps someone !
There is a problem with the zoom scale when rotating the phone and that will cause this problem, parts or the whole page will not be drawn. To solve this override onScaleChanged in your WebViewClient implementation and invalidate the view. That should force a redraw when needed.
#Override
public void onScaleChanged(WebView view, float oldScale, float newScale) {
if (view != null) {
view.invalidate();
}
}
Can anyone elaborate on what mobile browsers support multitouch, in particular the ability to press multiple "buttons" (or joysticks) at the same time? It is required for a game I'm making and would like to know, so I can switch to native app instead if necessary, though prefer not to.
If the answer is, it is generally not supported, does anyone happen to know a library/framework which can create screens from XML format or similar, like HTML, cross platform-wise and cross resolution-wise?
//get coordinates of 3 touch
function touch(e){
var touch1 = {x:e.changedTouches[0].clientX,y:e.changedTouches[0]};
var touch2 = {x:e.changedTouches[1].clientX,y:e.changedTouches[1]};
var touch3 = {x:e.changedTouches[2].clientX,y:e.changedTouches[2]};
}
you can get coordinates of each touch flowing up.
Multitouch is supported on Honeycomb and higher, and iOS 4 and higher.