How to set request orientation in runtime?

2020-04-19 06:43发布

问题:

I want my gluon application to be able to change orientation from Landscape to portrait in run time. I have check the Gluon Charmdown SDK, It seem that it have only getOrientation and don't have an option to set an orientation in runtime. I don't want to set fixed orientation in Manifest

回答1:

Charm Down has an OrientationService, but as you have mentioned, it is "read only", it just listens to orientation changes and gives you the current orientation at any time. But so far you can set the orientation programatically.

To include this feature there are two options: clone Charm Down, modify the Orientation Service, build and use your custom build, or directly create a new service, like ExtendedOrientationService, that you can include in your project directly.

Assuming the latter, this is a very basic implementation of a service that allows setting the orientation programmatically:

ExtendedOrientationService.java

package com.gluonhq.charm.down.plugins;

import javafx.geometry.Orientation;

public interface ExtendedOrientationService {

    void coerceOrientation(Orientation orientation);

    void releaseOrientation();

}

ExtendedOrientationServiceFactory.java

package com.gluonhq.charm.down.plugins;

import com.gluonhq.charm.down.DefaultServiceFactory;

public class ExtendedOrientationServiceFactory extends DefaultServiceFactory<ExtendedOrientationService> {

    public ExtendedOrientationServiceFactory() {
        super(ExtendedOrientationService.class);
    }

}

For Android:

AndroidExtendedOrientationService.java

package com.gluonhq.charm.down.plugins.android;

import android.content.pm.ActivityInfo;
import com.gluonhq.charm.down.plugins.ExtendedOrientationService;
import javafx.geometry.Orientation;
import javafxports.android.FXActivity;

public class AndroidExtendedOrientationService implements ExtendedOrientationService {

    private final FXActivity instance = FXActivity.getInstance();

    @Override
    public void coerceOrientation(Orientation orientation) {
        if (orientation.equals(Orientation.HORIZONTAL)) {
            instance.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        } else if (orientation.equals(Orientation.VERTICAL)) {
            instance.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
        instance.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
    }

    @Override
    public void releaseOrientation() {
        instance.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
    }

}

On iOS:

ExtendedOrientation.h

#import <UIKit/UIKit.h>
#include "jni.h"

@interface ExtendedOrientation : UIViewController {}
    @property (nonatomic, assign) BOOL shouldAutoRotate;

    - (void) setOrientation:(NSString *)orientation;
    - (void) release;
@end

ExtendedOrientation.m

#include "ExtendedOrientation.h"

extern JNIEnv *jEnv;
#define GET_MAIN_JENV \
if (jEnv == NULL) NSLog(@"ERROR: Java has been detached already, but someone is still trying to use it at %s:%s:%d\n", __FUNCTION__, __FILE__, __LINE__);\
JNIEnv *env = jEnv;

JNIEXPORT jint JNICALL
JNI_OnLoad_ExtendedOrientation(JavaVM *vm, void *reserved)
{
#ifdef JNI_VERSION_1_8
    //min. returned JNI_VERSION required by JDK8 for builtin libraries
    JNIEnv *env;
    if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_8) != JNI_OK) {
        return JNI_VERSION_1_4;
    }
    return JNI_VERSION_1_8;
#else
    return JNI_VERSION_1_4;
#endif
}

static int ExtendedOrientationInited = 0;

// ExtendedOrientation
ExtendedOrientation *_extendedOrientation;

JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_plugins_ios_IOSExtendedOrientationService_initOrientation
(JNIEnv *env, jclass jClass)
{
    if (ExtendedOrientationInited)
    {
        return;
    }
    ExtendedOrientationInited = 1;

    _extendedOrientation = [[ExtendedOrientation alloc] init];
}

JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_plugins_ios_IOSExtendedOrientationService_setOrientation
(JNIEnv *env, jclass jClass, jstring jOrientation)
{
    const jchar *charsOrientation = (*env)->GetStringChars(env, jOrientation, NULL);
    NSString *orientation = [NSString stringWithCharacters:(UniChar *)charsOrientation length:(*env)->GetStringLength(env, jOrientation)];
    (*env)->ReleaseStringChars(env, jOrientation, charsOrientation);
    [_extendedOrientation setOrientation:orientation];
}

JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_plugins_ios_IOSExtendedOrientationService_release
(JNIEnv *env, jclass jClass)
{
    [_extendedOrientation release];
}

@implementation ExtendedOrientation

-(void) setOrientation:(NSString*)orientation
{
    _shouldAutoRotate = YES;

    NSLog(@"Set orientation: %@", orientation);
    if ([orientation isEqualToString:@"HORIZONTAL"])
    {
        [[UIDevice currentDevice] setValue:[NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft] forKey:@"orientation"];
    } else
    {
        [[UIDevice currentDevice] setValue:[NSNumber numberWithInt:UIInterfaceOrientationPortrait] forKey:@"orientation"];
    }
}

- (void) release
{
    _shouldAutoRotate = NO;
}

- (BOOL)shouldAutorotate
{
    return _shouldAutoRotate;
}

@end

IOSExtendedOrientationService.java

package com.gluonhq.charm.down.plugins.ios;

import com.gluonhq.charm.down.plugins.ExtendedOrientationService;
import javafx.geometry.Orientation;

public class IOSExtendedOrientationService implements ExtendedOrientationService {

    static {
        System.loadLibrary("ExtendedOrientation");
        initOrientation();
    }

    @Override
    public void coerceOrientation(Orientation orientation) {
        setOrientation(orientation.toString());
    }

    @Override
    public void releaseOrientation() {
        release();
    }

    // native
    private static native void initOrientation();
    private static native void setOrientation(String orientation);
    private static native void release();

}

Now add the ios-gradle.build file from this sample.

Finally we need to build and include the native library:

build.gradle

apply from: 'ios-build.gradle'


task xcodebuild {
    doLast {
        xcodebuildIOS("$project.buildDir","$project.projectDir", "ExtendedOrientation")
    }
}

task installNativeLib (type:Copy, dependsOn: xcodebuild) {
    from("$project.buildDir/native")
    into("src/ios/jniLibs")
    include("*.a")
}

You can build and add the library to the project with:

./gradlew installNativeLib 

SAMPLE

This snippet shows how to use this service: If the orientation is vertical it will force horizontal orientation, else it will release the orientation:

Services.get(ExtendedOrientationService.class).ifPresent(o -> {
            Orientation orientation = Services.get(OrientationService.class)
                    .flatMap(OrientationService::getOrientation)
                    .orElse(Orientation.HORIZONTAL);

            if (orientation == Orientation.VERTICAL) {
                o.coerceOrientation(Orientation.HORIZONTAL);
            } else {
                o.releaseOrientation();
            }
        });