Persistent booleans Android Studio - android-studio

I've been poking around the web (including SO), and have found lots of information on having persistent data. I've found strings, ints, doubles, calendars, just about everything. The ones I haven't seen a specific guide or tutorial for are booleans.
I've created an app which has a switch located on the main activity. I do not have a settings button, window, or even a pane, because the entire app is accessed from the main activity. I want to have the switch be persistent as well as the affects it holds (ie, when the app is closed, it will remember if the user disable or enable the vibrate function).
I have the switch to work where it does enable the vibration depending on which position the switch is in. I can't seem to get the switch to remain in the off position when the app is recreated.
Here's my code to save:
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
dBell = MediaPlayer.create(this, R.raw.doorbell);
if ((bundle != null) && (bundle.getBoolean("vibetoggle") != false)) {
vibeOn = false;
} else {
vibeOn = true;
}
}
protected void onRestoreInstanceState(Bundle bundle) {
super.onRestoreInstanceState(bundle);
vibeOn = bundle.getBoolean("vibetoggle");
}
protected void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putBoolean("vibetoggle", vibeOn);
}
public void onToggleClicked(View view) {
Vibrator vibe = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
vibeOn = ((Switch) view).isChecked();
if (vibeOn) {
vibe.vibrate(100);
} else {
// No vibrate
}
}
public void playSound(View view) {
dBell.start();
if (vibeOn) {
Vibrator vibe = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
vibe.vibrate(300);
} else {
// No vibrate
}
}
The shorter duration vibrate (100ms) is occurs when the switch is flipped from disabled to enabled. The longer one is what actually causes the button to vibrate when clicked.
I've kind of gotten the boolean logic to work, but the IO switch would still be set to default and wouldn't function correctly until it had been switched. The issue I have regarding the switch, is that I want the switch to be in the correct position when loaded (ie, if the boolean is saved false, then the switch will load in the off position). I can't figure out how to make the two communicate. I would assume the switch would have to change based on the boolean, rather than the other way around. I just can't figure out how to make the xml switch communicate with the one I have in java and visa versa.
Here's the xml code for the switch:
<Switch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Vibration"
android:id="#+id/switch1"
android:layout_alignBottom="#+id/dBellButton"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:clickable="true"
android:checked="true"
android:onClick="onToggleClicked" />
I know the android:checked="true" causes the switch to be created in a default on position. I tried making a new boolean inside of the values xml (so rather than the code saying android:checked="true", it would say something along the lines of android:checked="#bool/vibeConvert), but found I didn't know how to edit the boolean through the java when it was there as well.
I've tried a few different methods to get this data to be persistent, but none of them worked for me. If I could get some help with persistent data, specifically regarding booleans, that would be fantastic.
EDIT: showing my attempt to use SharedPreferences.
protected void onRestoreInstanceState(Bundle bundle) {
super.onRestoreInstanceState(bundle);
vibeOn = bundle.getBoolean("vibetoggle");
// preferenceSettings = getPreferences(PREFERENCE_MODE_PRIVATE);
// vibeOn = preferenceSettings.getBoolean("on", true);
}
protected void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putBoolean("vibetoggle", vibeOn);
// preferenceSettings = getPreferences(PREFERENCE_MODE_PRIVATE);
// preferenceEditor = preferenceSettings.edit();
// preferenceEditor.putBoolean("on", vibeOn);
// preferenceEditor.apply();
}
I'm not quite sure how how to use the SharedPreferences, and I couldn't find anywhere which specified where to place them. They are commented out here for obvious reasons. Not sure where to go from here.
Thanks!
Nathan
EDIT:
I tried using the following code:
public static final String PREFS_NAME = "MyPrefsFile";
MediaPlayer dBell;
boolean vibeOn;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
dBell = MediaPlayer.create(this, R.raw.doorbell);
// Restore preferences
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean vibeSave = settings.getBoolean("vibeSave", vibeOn);
vibeOn = vibeSave;
Switch ("+id/switch1") = vibeSave;
}
#Override
protected void onStop() {
super.onStop();
// Let Editor make preference changes
// All objects are from android.context.Context
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("vibeSave", vibeOn);
editor.commit();
}
Here's my XML:
<Switch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Vibration"
android:id="#+id/switch1"
android:layout_alignBottom="#+id/dBellButton"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:clickable="true"
android:checked="true"
android:onClick="onToggleClicked" />
I'm not sure if:
The boolean value is being saved.
The switch can be edited inside of the java code.
I've tried to play with the idea with the following line of code: Switch ("+id/switch1") = vibeSave;, but that didn't work. I'm not sure how to proceed from here. I want my XML to be able to start in the correct position based on the value in the boolean, but I'm not sure how to make my XML and my java talk to each other.

You can use SharedPreferences to store primitive values.
The best place to do this, is right after the value is changed.
So add the saving to the logic of your switch listener, and the loading to the logic of your switch initializer.
To get a SharedPreferences object for your application, use one of two
methods:
getSharedPreferences() - Use this if you need multiple preferences
files identified by name, which you specify with the first parameter.
getPreferences() - Use this if you need only one preferences file for
your Activity. Because this will be the only preferences file for your
Activity, you don't supply a name.
To write values:
Call edit() to get a SharedPreferences.Editor.
Add values with methods such as putBoolean() and putString().
Commit the new values with commit()
To read values, use SharedPreferences methods such as getBoolean() and getString().
The code in your onCreate should look something like this:
#Override
protected void onCreate(Bundle bundle) {
(...)
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean vibeSave = settings.getBoolean("vibeSave", false);
Switch switch = (Switch) findViewById(R.id.switch1);
switch.setChecked(vibeSave);
}

Related

How to fix setOnClickListener code that causes crash

I am having difficulty in figuring out what is wrong with my code, My code runs when the onclick listener is not yet implemented but once I implement the onclick listener it crashes.
public class menu extends AppCompatActivity implements View.OnClickListener {
private CardView assess, profile, chatbot, breathing;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menu);
assess = (CardView) findViewById(R.id.assess);
profile = (CardView) findViewById(R.id.profile);
chatbot = (CardView) findViewById(R.id.chatbot);
breathing = (CardView) findViewById(R.id.breathing);
// assess.setOnClickListener(this);
// profile.setOnClickListener(this);
// chatbot.setOnClickListener(this);
// breathing.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// Intent i;
//
// switch (v.getId()){
//
//
// case R.id.assess :
// i = new Intent(this,depression_assessment.class);
// startActivity(i);
// break;
}
}
//}
When I tried debugging the codes, these lines are the cause of the crash.
// assess.setOnClickListener(this);
// profile.setOnClickListener(this);
// chatbot.setOnClickListener(this);
// breathing.setOnClickListener(this);
It is where the problem is starting because the code works even though the onclick is blank. When I checked the logs it shows this error
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.thesis/com.example.thesis.menu}:
java.lang.NullPointerException: Attempt to invoke virtual method 'void
androidx.cardview.widget.CardView.setOnClickListener(android.view.View$OnClickListener)'
on a null object reference
You haven't shown enough code, but this could be due to serveral reasons:
This line of code breathing = (CardView) findViewById(R.id.breathing); will look for a view with id breathing inside your activity's layout, and according to the error it is null, which means it did not find it within the same activity's layout, so make sure your cardView is in this activity's layout. Another possible reason is that you might have duplicate Ids in your xml files, in this case,find the duplicate and rename the Ids.

Intellij Idea Live Template to create field and method at same time

How to create field variable automatically when I create method used that field. I've create template like this:
void $METHOD_NAME$() {
$FIELD_NAME$ = true;
}
when I type field name (e.g. mState) in method will create field as:
private boolean mState = false;
Hope someone help. Sorry my bad.
Given the screenshot of your template, you can also create a field with the following live template:
private boolean $param$ = false;
#Override
public void onBackPressed() {
if ($param$) super.onBackPressed();
android.widget.Toast.makeText(this, "$message$",
android.widget.Toast.LENGTH_SHORT).show();
$param$ = true;
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
$param$ = false;
}
}, 100);
}
Where $param$ and $message$ are regular variables without anything special.
However, like I said in the comment on your question, I suggest to split it up in several smaller templates.
Consider to split it up in:
field + method with just:
private boolean $param$ = false;
#Override
public void onBackPressed() {
if ($param$) super.onBackPressed();
$param$ = true;
}
Then create a template for the message:
android.widget.Toast.makeText(this, "$message$", android.widget.Toast.LENGTH_SHORT).show();
And last but not least, create a template for the postDelayed:
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
$END$
}
}, $delay$);
Note: the $delay$ as a bonus you can even give it a default value or create a list of predefined values for ease of use.
Note2: Instead of $param$ = false; I've replaced it with $END$. This will position your cursor here once you've selected the delay. Now you can type mState = false manually here, or whatever code you need in the context at that moment. This makes the template much more flexible and easier to use.
PS. I suppose you want to call super.onBackPressed() only when the value is false (on the first invocation). In that case use if (!$param$) instead.
// Update:
In order to group the newly added field with the other fields and not halfway somewhere in your class between other methods, rearrange the code
via the menu with: Code -> rearrange code.
To customise this, check your arrangement settings under: settings -> code style -> <language> -> arrangement

How to set EXTRA_PAGE and EXTRA_PAGE_SIZE in a MediaBrowserServiceCompat by getting reference to the Android Auto MediaBrowser?

I have an Android Auto app. I would like to take advantage of pagination for browsing within the app. It seems that you can set EXTRA_PAGE and EXTRA_PAGE_SIZE by getting a reference to the MediaBrowserCompat and passing those constants in .subscribe(). However, I can't figure out how to get a reference to the MediaBrowserCompat that Android Auto Audio uses in order to call .subscribe().
This seems way too complicated for something that should be simple, am I just overthinking things?
How to get the reference to the Android Auto MediaBrowser?
For it, you suppose to know the package name and the class name (if you are trying to bind it outside the app). If you don't know the these details, you can just get it all from the package manager.
final Intent providerIntent =
new Intent(MediaBrowserService.SERVICE_INTERFACE);
List<ResolveInfo> mediaApps =
mPackageManager.queryIntentServices(providerIntent, 0);
for (ResolveInfo info : mediaApps) {
new MediaBrowserCompat(context,
new ComponentName(info.serviceInfo.packageName,
info.serviceInfo.name), mConnectionCallbacks, null);
}
How to set EXTRA_PAGE and EXTRA_PAGE_SIZE?
Bundle bundle = new Bundle();
bundle.putInt(MediaBrowserCompat.EXTRA_PAGE, 1);
bundle.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, 1);
mBrowser.subscribe("__SOME_ID__", bundle, callback);
If you are overriding the onLoadChildren() with the bundle on your service side than you have to handle the paging logic too. You can bypass it by just overriding onLoadChildren without bundle.
Please note: Usually in Android when you see compat suffix at the end, it is new (enhanced) version of one without compat.
MediaActivity is not special Activity, it's a kind of Activity, which is designed to play the musics. And, as you asked MediaBrowserCompat and MediaBrowserServiceCompat, I changed my default architecture (Architecture 2 presented below), to Architecture 1 (Architecture 1 presented below which is new introduced in version 22), just to give the exact answer that you asked.
Two Architectures are:
Architecture1)
1) MediaActivity <--uses----> MediaBrowserCompat <---uses--> MediaServiceBrowserCompat <----> MediaSessionCompat <---> MediaSession <--pass session token --> MediaControllerCompat <-- it also passes token to create --> MediaController /* latest API introduced in 22 */
2)
<service android:name=".MyMediaBrowserServiceCompat"
android:label="#string/service_name" >
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
3) Uses MediaSessionCompat to control music playing.
4) Once a session is created the owner of the session may pass its session token to other processes to allow them to create a MediaControllerCompat to interact with the session.
5) A MediaController can be created if you have a MediaSessionCompat.Token from the session owner.
Now, You created MediaController
From here, both Architecture do the same thing.
Architecture2)
1)MediaActivity <--uses----> MediaBrowser <---uses--> MediaServiceBrowser /* old one introduced in 21. This is default */
2)
<service android:name=".MyMediaBrowserService"
android:label="#string/service_name" >
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
3) Uses MediaSession to control music playing
4) Once a session is created the owner of the session may pass its session token to other processes to allow them to create a MediaController to interact with the session.
5) A MediaController can be created through MediaSessionManager if you hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or are an enabled notification listener or by getting a MediaSession.Token directly from the session owner.
Now, You created MediaController
From here, both Architecture do the same thing.
Note: By default, when you create Android Auto project, it still uses Architecture 2, But, I'm using Architecture 1 because you asked to do via MediaBrowserCompat. So, you can be a little confused here.
Since exact implementation is kind of long, so I'm providing exact link where you kind find the implementation via MediaBrowserCompat way (Architecture 1)
https://github.com/googlesamples/android-MediaBrowserService
I am posting basic code here based on the Architecture -- because it's a new one introduced in version 22 -- just to enough to show how you can get MediaBrowserCompat reference.
mConnectionCallbacks is the main thing that connectes MediaServiceBrowserCompat with MediaBrowserCompat. MediaBrowserCompat controls the media provided by the MediaServiceBrowserCompat. Activity, which is suitablely designed to control the media is called MediaActivity. MediaActivity uses MediaBrowserCompat to control media (eg, volume, play change etc). MediaBrowserCompat setups mConnectionCallbacks which further has onConnected() etc methods where you can put your own logic there.
public class MyMediaActivity /* can be any activity */ extends AppCompatActivity {
private MediaBrowserCompat mMediaBrowserCompat; /* your reference here */
MediaControllerCompat mediaController = MediaControllerCompat.getMediaController(MyMediaActivity.this);
MediaControllerCompat.Callback controllerCallback =
new MediaControllerCompat.Callback() {
#Override
public void onMetadataChanged(MediaMetadataCompat metadata) {
}
#Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {
}
};
private MediaBrowserCompat.ConnectionCallback mConnectionCallbacks =
new MediaBrowserCompat.ConnectionCallback() {
#Override
public void onConnected() {
// Get the token for the MediaSession
MediaSessionCompat.Token token = mMediaBrowserCompat.getSessionToken();
// Create a MediaControllerCompat
MediaControllerCompat mediaController =
null;
try {
mediaController = new MediaControllerCompat(MyMediaActivity.this, // Context
token);
} catch (RemoteException e) {
e.printStackTrace();
}
// Save the controller
MediaControllerCompat.setMediaController(MyMediaActivity.this, mediaController);
// Finish building the UI
buildTransportControls();
}
#Override
public void onConnectionSuspended() {
// The Service has crashed. Disable transport controls until it automatically reconnects
}
#Override
public void onConnectionFailed() {
// The Service has refused our connection
}
};
void buildTransportControls() {
/* you can define your view to control music here */
/* your stuffs here */
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Display the initial state
MediaMetadataCompat metadata = mediaController.getMetadata();
PlaybackStateCompat pbState = mediaController.getPlaybackState();
// Register a Callback to stay in sync
mediaController.registerCallback(controllerCallback);
mConnectionCallbacks = new MediaBrowserCompat.ConnectionCallback();
/* your MediaBrowserCompat instance reference here*/
mMediaBrowserCompat = new MediaBrowserCompat(this,
new ComponentName(this, MyMediaBrowserServiceCompat.class),
mConnectionCallbacks,
null); // optional Bundle
/* now you can call subscribe() callbacks via mMediaBrowserCompat.subscribe(.....) anywhere inside this Activity's
lifecycle callbacks
*/
}
#Override
public void onStart() {
super.onStart();
mMediaBrowserCompat.connect();
}
#Override
public void onStop() {
super.onStop();
// (see "stay in sync with the MediaSession")
if (MediaControllerCompat.getMediaController(MyMediaActivity.this) != null) {
MediaControllerCompat.getMediaController(MyMediaActivity.this).unregisterCallback(controllerCallback);
}
mMediaBrowserCompat.disconnect();
}
}
And, now, you can create MediaBrowserServiceCompat /* note MediaBrowserServiceCompat is service */ as below.
public class MyMediaBrowserServiceCompat extends MediaBrowserServiceCompat {
/* various calbacks here */
}
For more research, you can read this link, which exactly explains the logic I presented above.
https://developer.android.com/guide/topics/media-apps/audio-app/building-a-mediabrowser-client.html#connect-ui-and-mediacontroller

MvvmCross and UIButton.Selected UISegmentedControl Bindings, iOS

In a cross platform Xamarin app built with the MvvmCross framework I'm using a ToggleButton Widget in an Android .axml layout. I've bound the Checked property to a View Model property using a converter using the following binding syntax:
Checked MarketBuySellViewModel.Direction, Converter=DirectionBool, ConverterParameter='Sell'
Everything works well. On the iOS side, it appears you can use UIButton as a ToggleButton by using the Selected property. This implies that the following binding should achieve what I want on iOS:
set.Bind (SellButton).For(b => b.Selected).To (vm => vm.MarketBuySellViewModel.Direction).WithConversion("DirectionBool", "Sell");
I don't get any binding errors in the application output but the binding itself doesn't seem to work. Clicking the button doesn't set the Direction property and setting the direction to a different value does not set the Selected property on the UIButton.
Do I need to create a Custom Binding or am I simply setting up the binding incorrectly?
I also tried using a UISegmentedControl to achieve the same effect. Is binding to this control supported at all in MvvmCross? I don't see any reference to it in the source code. Does this mean I need to create custom bindings for it too?
For the UIButton, I don't believe there's any included Selected binding built into MvvmCross. Because of this - and because Selected doesn't have a simple paired event SelectedChanged, then I believe Selected binding should work one-way (from ViewModel to View) but not two-way.
There is a binding for the On of a UISwitch control and that's the control I've seen used most in these situations.
If you wanted to add a custom 2-way binding for Selected then I guess you'd have to do this using the ValueChanged event (but would need to check that is correct).
To do so, you'd just build a target binding something like:
public class MvxUIButtonSelectedTargetBinding : MvxPropertyInfoTargetBinding<UIButton>
{
public MvxUIButtonSelectedTargetBinding(object target, PropertyInfo targetPropertyInfo)
: base(target, targetPropertyInfo)
{
var view = View;
view.ValueChanged += HandleValueChanged;
}
private void HandleValueChanged(object sender, System.EventArgs e)
{
var view = View;
if (view == null)
return;
FireValueChanged(view.Selected);
}
public override MvxBindingMode DefaultMode
{
get { return MvxBindingMode.TwoWay; }
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (isDisposing)
{
var view = View;
if (view != null)
{
view.ValueChanged -= HandleValueChanged;
}
}
}
}
and this could be registered in Setup in protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry) using something like:
registry.RegisterPropertyInfoBindingFactory(typeof(MvxUIButtonSelectedTargetBinding), typeof(UIButton),
"Selected");
Similarly, I don't believe anyone has added a two way UISegmentedControl binding yet - but would happily see one added.
Building a two way UISegmentedControl binding would be quite straight-forward - you'd just have to bind to the pair SelectedSegment and ValueChanged - with code similar to above.
Alternatively, you could switch to using a custom MySegmentedControl which had a nicer Value`ValueChanged` pair which would automatically work without a custom binding - e.g.:
public class MySegmentedControl : UISegmentedControl
{
// add more constructors if required
public int Value
{
get { return base.SelectedSegment; }
set { base.SelectedSegment = value; }
}
}
If any or all of these custom bindings are needed, then the Mvx project is happy to get these bindings added as issues or pull requests along with test/demo UIs in the https://github.com/slodge/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Touch/Views/FirstView.cs project
Could be helpful to someone else, so i'm sharing my experience. I needed a two way binding for UISegmentedControl.SelectedSegment property to a ViewModel. The one way biding (ViewModel => View) works by default. I couldn't able to properly utilize the solution proposed by Stuart - to subclass the UISegmentedControl. I tried to ensure that the linker does not rip off the new custom control code, but this didn't help me a bit. So a perfectly viable solution is the one with MvxPropertyInfoTargetBinding. Here is the code working ok for me:
public class MvxUISegmentedControlSelectedSegmentTargetBinding : MvxPropertyInfoTargetBinding<UISegmentedControl>
{
public MvxUISegmentedControlSelectedSegmentTargetBinding(object target, PropertyInfo targetPropertyInfo)
: base(target, targetPropertyInfo)
{
this.View.ValueChanged += HandleValueChanged;
}
private void HandleValueChanged(object sender, System.EventArgs e)
{
var view = this.View;
if (view == null)
{
return;
}
FireValueChanged(view.SelectedSegment);
}
public override MvxBindingMode DefaultMode
{
get { return MvxBindingMode.TwoWay; }
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (isDisposing)
{
var view = this.View;
if (view != null)
{
view.ValueChanged -= HandleValueChanged;
}
}
}
}
public class Setup : MvxTouchSetup
{
...
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
registry.RegisterPropertyInfoBindingFactory(typeof(MvxUISegmentedControlSelectedSegmentTargetBinding), typeof(UISegmentedControl), "SelectedSegment");
}
}

How to use QLPreviewController in a non-modal way? Why does my code not work?

I have QLPreviewController up and running but I'm using PresentModalViewController() to show the QLPreviewController directly. For reasons beyond explanation, I would like to have my own UIViewController which will create its own view and within that view I would like to use the QLPreviewController. Should be easy I thought, but the code below just does nothing. The QLPreviewControllers ViewDidAppear never gets called. (In my example below, PreviewController inherits from QLPreviewController and encapsulates delegate, preview item and source).
Can somebody explain what is wrong with the code below (besides the fact that it is pointless :-))?
Oh, yeah: in my test scenario, I present the controller below modally. It shows up but witout the preview.
public class OuterPreviewController : UIViewController
{
public OuterPreviewController (QLPreviewControllerDataSource oDataSource) : base()
{
this.oDataSource = oDataSource;
}
private PreviewController oPreviewController;
private QLPreviewControllerDataSource oDataSource;
public override void LoadView ()
{
this.View = new UIView();
this.View.Frame = new RectangleF(0, 0, 500, 500);
this.View.BackgroundColor = UIColor.Red;
}
public override void ViewDidAppear (bool animated)
{
// Code execution comes her. No errors, no issues.
base.ViewDidAppear (animated);
this.oPreviewController = new PreviewController();
this.oPreviewController.DataSource = this.oDataSource;
// Preview controller's view is added but it never shows up.
this.View.AddSubview(this.oPreviewController.View);
this.oPreviewController.View.Frame = this.View.Frame;
this.oPreviewController.View.Center = this.View.Center;
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
Found a solution by coincidence today: all ReloadData() on the preview controller and magically it will show its contents.
This allows to add a QLPreviewController to an existing view as a subview and embed a preview. It also gets you rid of the toolbar which contains the open in menu.

Resources