I have a drawing activity that creates a custom 'canvas' View that occupies the entire screen, allowing the user to draw on it. I have a requirement to lock the Activity to the portrait orientation, as the drawing app is a sketchpad replacement, and the user would have the need to rotate the 'pad' to draw without the pad flipping around on them. This of course means that the Options Menu is locked to that orientation as well and depending on the user, the menu could be popping out of the top, bottom or sides. I'd like to have the Options Menu always be located at the bottom relative to the user... some options I am considering and would appreciate any suggestions or info:
Allow orientation changes, so the menu moves as needed, then use the SensorManager to listen for the orientation, and manually rotate the canvas View back to the 'correct' orientation (portrait). This would be ugly, as there could be a delay in the rotation of the canvas, and it introduces some potentially complex calculations, etc due to the X/Y being swapped.
Restrict orientation changes, then use the SensorManager to listen for the orientation, and manually rotate the Options Menu back to the bottom. No idea if this is possible.
Lock orientation, and create a custom View that intercepts the menu button and displays a 'fake' Options Menu that I need to manage, etc. Really really don't want to have to replace built-in OS functionality, could be a nightmare to maitain for different versions of OS in future, etc.
Anyone have any ideas on how to handle this? I'd love if #2 was possible, but can't find anything related to that.
Thanks,
Paul
EDIT:
Have confirmed that #2 is not possible, so I guess my options are #1, #3, unless anyone else has any ideas?
My solution is as follows:
Allow normal orientation changes in the Android Manifest for the Activity.
In the custom 'canvas' view constructor, fire up a tracking field, mDisplay, that gets the display information via:
Code:
mDisplay = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
In onDraw(), check to see if the display rotation is something other than 0, and rotate the canvas back to the 0 rotation value:
Code:
if (mDisplay.getRotation() > 0) {
canvas.save(Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);
canvas.rotate(-mDisplay.getRotation(), px, py);
...
do stuff
...
canvas.restore();
}
Not sure that it's the best solution, but it seems to work.
Related
Please note: This question is about Qt C++ framework, not normal Java API. In Java, this question has already been answered.
In the main menu of my application, I really don't want to worry about different kinds of screen rotation. I would like to disable screen rotation until user goes to other views where screen rotation is meaningful. For main menu, I want to use portrait view only.
How to achieve that? How to control app screen rotation?
You can set the orientation using
QAndroidJniObject activity = QtAndroid::androidActivity();
activity.callMethod<void>("setRequestedOrientation", "(I)V", orientation);
where orientation is an int representing the orientation. You can copy the codes provided in the documentation (e.g., 0 to lock landscape, 1 to lock portrait and -1 to unlock any rotation), but I recommend to use, e.g.,
QAndroidJniObject::getStaticField<int>("android.content.pm.ActivityInfo", "SCREEN_ORIENTATION_LANDSCAPE");
to get the code values.
This answer is based on https://stackoverflow.com/a/38947312/4248972. The difference is that this answer also explains how to unlock rotation again and provides a sample to show how to get the orientation codes without manual copying.
Sorry for my bad english.
I develop a game in which will be implemented autoOrientation, but when i rotate device and stage orientation is changed, then reinitialization process take too long time (because i use GPU to render game content), therefore i decided to disable autoOrientation and manually calculate the orientation of the device from accelerometer data, and then rotate the main game sprite accordingly to calculated orientation...and it works, but SystemBar remains static in its first position when game was launched. The question is how to set SystemBar position in Android, something like this
SetBarPosition(TOP / BOTTOM / RIGHT / LEFT);
In this case you should handle the orientation change yourself instead of disabling it. On android you should implement onConfigurationChanged() method and add to manifest that you handle orientation changes.
Without going into too much detail, I want to be able to 'slide' elements in a ListView similar to the 'slide to archive' feature in GMail. I'm fine with the onTouchListener and all that, my question is regarding the slide animation.
The first two things that come to mind are..
view.setPadding(slideOffset, 0, 0, 0);
and..
view.setX(slideOffset);
The former is very buttery, even on the emulator.
The latter is a bit janky on my Galaxy Nexus.
My questions:
* Regardless of what I've tried, what's the correct way to do this?
Why is setX less smooth than setPadding?
Does one approach conform to Android best practices more than the other?
Are tweened translation animations an option? If so, can you provide a brief example to point me in the right direction please?
Edit:
To be clear, I am attaching an image of the effect I am trying to emulate.
I'm pretty sure the setX() is slower because it affects its parents. When changing the X of a view, it calls the onLayout/onMeasure of the parent every time you update the value. That's because the X value of the child may cause other items on the parent to move, therefor the parent needs to redraw itself.
You can test this easily by extending the ViewGroup and writing to the log on those methods. Then, you can use both approaches, padding vs. setX, and see what happens.
Are you trying to animate the item? Or do you want the user to move it like on Gmail? You can use the ObjectAnimator to handle the "X" value of your item. Combined with a "hardware layer" for your item, it will create a smoother experience. You can find more details about how to do that here: http://developer.android.com/guide/topics/graphics/hardware-accel.html
Yeah, if you're targeting higher APIs, ViewPropertyAnimator is probably a great solution. If you have to support lower APIs, my thought process for implementation would be (and I haven't implemented this myself personally, but this should be good for performance) to:
In your touch handler, once you've determined that the user is "sliding", set the View's visibility to INVISIBLE, and store the drawing cache into a separate bitmap (Bitmap bmp = myView.getDrawingCache();)
Draw that bitmap in the same place as the view, and use the Canvas translate methods to shift the position according to the x-position of the user's touch point.
After the user lets go, translate back (preferably smoothly with an animation), recycle the bitmap, and set the view back to VISIBLE.
Check out the 3 devBytes posted on AndroidDev:
https://www.youtube.com/watch?v=8MIfSxgsHIs&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=12
https://www.youtube.com/watch?v=NewCSg2JKLk&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=11
https://www.youtube.com/watch?v=NewCSg2JKLk&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=11
https://www.youtube.com/watch?v=YCHNAi9kJI4&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=4
https://www.youtube.com/watch?v=PeuVuoa13S8&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=3
I'm doing a live wallpaper. However, what is initially shown depends on the number of home screens.
While onOffsetsChanged() allows you to calculate the number of home screens, it gets called only if the user scrolls the homescreen.
So is there a way to get the current xStep and xOffSet without calling onOffSetsChanged()?
Edit: I may not need to know that per se. Here's what I'm doing: I'm basically drawing a portion of the bitmap. The portion shown depends on the current homescreen.
Edit 2: so to explain what I'm trying to do---I'm basically trying to mimick the scrolling wallpaper effect but with a video. The point is that the portion shown depends on the current homescreen. Here's the problem: So the user selects the wallpaper. OnSurfaceCreated() is called, followed by onSurfaceChanged(). However, onOffSetsChanged() is never called until the user tries to scroll the homescreens. That's the problem. You don't know what part of the bitmap/video to display until the user scrolls the screen. (So Josh's suggestion doesn't work. The part of the video that's displayed may be wrong---until the user scrolls the screen and we get the correct onOffSetsChanged() values.)
Your edit doesn't really explain why you need to know how many screens there are. You can draw the center portion of your bitmap initially, then when xOffset changes to something like 0, draw the leftmost portion of your bitmap. What's the issue?
I'm working on my Live Wallpaper and I want it to scroll with the screen like a normal wallpaper does. I know I need to use onOffsetsChanged() but which parameter will tell me the direction that the home screen is being swiped? It seems like xOffset always returns a positive value no matter which way the screen slides.
Thank you.
The direction alone will not help you: you need to know the exact offset, because the user may have jumped several screens at once (e.g. by using a pop-up that displays mini-versions of all the home screens).
Generally speaking, you want to save the xPixel value you get in onOffsetsChanged, then use this to translate your canvas.
See my two answers below:
onOffsetsChanged: move Bitmap
android live wallpaper rescaling