1

画面の一部にカスタマイズされたビデオ プレーヤーを表示する iOS および Android 用のアプリを作成することになっています。私はそれを制御できなければなりません (シーク、再生、一時停止、速度の設定、ビデオの選択...)。そのようなメディアは Gluon ではまだサポートされていません。

しかし、そのようなことを XCode と Android Studio で記述し、何らかの方法で Gluon アプリに埋め込むことは可能でしょうか?

4

2 に答える 2

1

Gluon Charm Downライブラリの設計パターンに従って、これは基本的な Android 実装のVideoService.

このチュートリアルに基づいておりSurfaceView、JavaFX が現在使用している環境で使用できるように調整されています。TextureView画面の中央、現在のビューの上に配置されるを作成し、幅の 95% を取ります。

IDE 用の Gluon プラグインを使用して、Single View Project を作成します。

  1. 次の 2 つのクラスをソース パッケージの package の下に配置しますcom.gluonhq.charm.down.plugins

VideoService インターフェース

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);
    }

}
  1. Android パッケージ: このクラスを Android/Java パッケージ、package の下に配置します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());
        }
    }
}
  1. サンプル

動画ファイルを android/assets フォルダーに置きます。ここbig_buck_bunny.mp4からダウンロードできます。

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 が一番上にあることに注意してください。

于 2016-12-17T20:10:57.107 に答える