我应该为iOS和Android编写应用程序,有时会在屏幕的一部分上显示自定义的视频播放器。我必须能够控制它(寻找,播放,暂停,设定速度,选择视频......)。我知道Gluon尚不支持此类媒体。
但是可以在XCode和Android Studio中编写这样的东西并以某种方式将其嵌入到Gluon应用程序中吗?
答案 0 :(得分:1)
遵循Gluon Charm Down library中的设计模式,这可能是VideoService
的基本Android实现。
它基于此tutorial,适用于JavaFX使用的当前SurfaceView
。它将创建一个TextureView
,它将放置在屏幕中央,位于当前视图的顶部,占据其宽度的95%。
使用IDE的Gluon插件,创建一个单视图项目。
com.gluonhq.charm.down.plugins
:视频服务界面
package com.gluonhq.charm.down.plugins;
public interface VideoService {
void play(String videoName);
void stop();
void pause();
void resume();
}
VideoServiceFactory类
package com.gluonhq.charm.down.plugins;
import com.gluonhq.charm.down.DefaultServiceFactory;
public class VideoServiceFactory extends DefaultServiceFactory<VideoService> {
public VideoServiceFactory() {
super(VideoService.class);
}
}
com.gluonhq.charm.down.plugins.android
:AndroidVideoService类
package com.gluonhq.charm.down.plugins.android;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.graphics.SurfaceTexture;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import com.gluonhq.charm.down.plugins.VideoService;
import java.io.IOException;
import javafxports.android.FXActivity;
public class AndroidVideoService implements VideoService, TextureView.SurfaceTextureListener {
private static final String TAG = AndroidVideoService.class.getName();
private MediaPlayer mMediaPlayer;
private String videoName;
private final RelativeLayout relativeLayout;
private final TextureView textureView;
private final DisplayMetrics displayMetrics;
public AndroidVideoService() {
displayMetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) FXActivity.getInstance().getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
relativeLayout = new RelativeLayout(FXActivity.getInstance());
textureView = new TextureView(FXActivity.getInstance());
textureView.setSurfaceTextureListener(this);
relativeLayout.addView(textureView);
}
@Override
public void play(String videoName) {
this.videoName = videoName;
stop();
FXActivity.getInstance().runOnUiThread(() -> {
FXActivity.getViewGroup().addView(relativeLayout);
});
}
@Override
public void stop() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
if (relativeLayout != null) {
FXActivity.getInstance().runOnUiThread(() -> {
FXActivity.getViewGroup().removeView(relativeLayout);
});
}
}
@Override
public void pause() {
if (mMediaPlayer != null) {
mMediaPlayer.pause();
}
}
@Override
public void resume() {
if (mMediaPlayer != null) {
mMediaPlayer.start();
}
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture st, int i, int i1) {
Surface surface = new Surface(st);
try {
AssetFileDescriptor afd = FXActivity.getInstance().getAssets().openFd(videoName);
calculateVideoSize(afd);
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mMediaPlayer.setSurface(surface);
mMediaPlayer.setLooping(true);
mMediaPlayer.prepareAsync();
mMediaPlayer.setOnPreparedListener(mediaPlayer -> mediaPlayer.start());
} catch (IllegalArgumentException | SecurityException | IllegalStateException | IOException e) {
Log.d(TAG, e.getMessage());
}
}
@Override public void onSurfaceTextureSizeChanged(SurfaceTexture st, int i, int i1) { }
@Override public boolean onSurfaceTextureDestroyed(SurfaceTexture st) { return true; }
@Override public void onSurfaceTextureUpdated(SurfaceTexture st) { }
private void calculateVideoSize(AssetFileDescriptor afd) {
try {
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
String height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
String width = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
double factor = Double.parseDouble(width) > 0 ? Double.parseDouble(height) / Double.parseDouble(width) : 1d;
// 95% screen width
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((int) (0.95 * displayMetrics.widthPixels),
(int) (0.95 * displayMetrics.widthPixels * factor));
lp.addRule(RelativeLayout.CENTER_IN_PARENT);
textureView.setLayoutParams(lp);
} catch (NumberFormatException e) {
Log.d(TAG, e.getMessage());
}
}
}
将视频文件放在android / assets文件夹中,例如big_buck_bunny.mp4
,可以从here下载。
<强> BasicView 强>
public class BasicView extends View {
private boolean paused;
public BasicView(String name) {
super(name);
}
@Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MENU.button());
appBar.setTitleText("Video View");
// big_buck_bunny.mp4 video in src/android/assets:
Services.get(VideoService.class).ifPresent(video -> {
appBar.getActionItems().add(MaterialDesignIcon.PLAY_ARROW.button(e -> video.play("big_buck_bunny.mp4")));
appBar.getActionItems().add(MaterialDesignIcon.PAUSE.button(e -> {
if (!paused) {
video.pause();
paused = true;
} else {
video.resume();
paused = false;
}
}));
appBar.getActionItems().add(MaterialDesignIcon.STOP.button(e -> video.stop()));
});
}
}
在您的Android设备上部署并测试:
请注意,TextureView将位于顶部,直到您按下停止按钮将其删除。
答案 1 :(得分:0)
以下示例中使用了原生视频播放器(或者在这种情况下是&#34;预览&#34;视频的方法):
https://gist.github.com/bgmf/d87a2bac0a5623f359637a3da334f980
除了一些先决条件,代码如下所示:
package my.application;
import ch.cnlab.disentis.util.Constants;
import org.robovm.apple.foundation.*;
import org.robovm.apple.uikit.UIApplication;
import org.robovm.apple.uikit.UIDocumentInteractionController;
import org.robovm.apple.uikit.UIDocumentInteractionControllerDelegateAdapter;
import org.robovm.apple.uikit.UIViewController;
import java.io.File;
import java.util.logging.Logger;
public class NativeVideoServiceIOS extends PathHelperIOS implements NativeVideoService {
private static final Logger LOG = Logger.getLogger(NativeVideoServiceIOS.class.getName());
public NativeVideoServiceIOS() {
LOG.warning("Initialized Native Video Service with path: " + this.pathBase);
}
@Override
public void triggerPlatformApp(String filename) {
String fullfile = pathBase.getAbsolutePath() + filename;
NSURL url = new NSURL(NSURLScheme.File, "", fullfile);
UIDocumentInteractionController popup = new UIDocumentInteractionController(url);
popup.setDelegate(new UIDocumentInteractionControllerDelegateAdapter() {
@Override
public UIViewController getViewControllerForPreview(UIDocumentInteractionController controller) {
return UIApplication.getSharedApplication()
.getWindows().first().getRootViewController();
}
});
popup.presentPreview(true);
}
}