Firemonkey使用Android原生控件一些注意事项
阅读原文时间:2021年04月20日阅读:1

Firemonkey使用MediaPlayer时是没有事件的,需要自己处理,一般在Windows下就算了,大把的播放器可以用,但在Android下比较麻烦,本人尝试用FFMpeg,但编译的so库只支持v7a架构,低级设备支持不好,而且没有编译硬件解码,所以播放时漏帧严重,MediaPlayer也不是个好东西,10.3以下的顶层遮盖问题,10.3以上取不到时间、状态(始终是Stop),所以要解决好几个问题才能满足本人的要求:(本人要求从头播放一个小视频,结束后再播放下一个,右上角可以显示一个图标,下面要显示一个滚动字幕)

研究了一下FMX.Media.Android.pas,决定还是自己封装一个JVideoView

一、播放器事件Listener

网上找了一圈在CSDN上ssxbxk作者倒是写了实现JNI监听器的方法,可惜没写具体使用方法,失败很多次最后才成功。

步骤如下:

1、Delplhi 实现Java Jar包中的Listener,这是ssxbxk作者的原文

2、我要实现的是播放器完成事件,所以使用是JVideoView.setOnCompletionListener

按Ctrl+鼠标左键,找到Androidapi.JNI.Media.pas中的声明,XE10.2.3版本中在2979行位置

  [JavaSignature('android/media/MediaPlayer$OnCompletionListener')]
  JMediaPlayer_OnCompletionListener = interface(IJavaInstance)
    ['{855040E1-8E41-40EE-B36F-06C212B8AC81}']
    procedure onCompletion(mp: JMediaPlayer); cdecl;
  end;

说明只有一个onCompletion方法,下面要实现一个新的类

type
  TOnCompletionListener = class(TJavaLocal, JMediaPlayer_OnCompletionListener)
  private
    [Weak] FParent: TFrmMain;
  public
    constructor Create(Parent: TFrmMain);

    procedure onCompletion(mp: JMediaPlayer); cdecl;
  end;

//--以下是实现部分


{ TOnCompletionListener }

constructor TOnCompletionListener.Create(Parent: TFrmMain);
begin
  inherited Create;
  FParent := Parent;
end;

procedure TOnCompletionListener.onCompletion(mp: JMediaPlayer);
begin
  CallInUIThreadAndWaitFinishing(
  procedure
  begin
    FParent.OnCompleteion(FParent);//调用TFrmMain中的NotifyEvent事件
  end);
end;

最后使用这个监听器实例,上面那个blog中没有写这部分

var
  completion_event: TOnCompletionListener = nil;//定义成全局的,反正不能定义在栈里(方法的Begin前面)

//--创建监听器实例,再设置成JViewView里
completion_event := TOnCompletionListener.Create(Self);
FVideoView.setOnCompletionListener(completion_event);//生成播放完成事件类实例

二、在JViewView上插入原生的JImageView,用来显示图片

说实话,不会点Android,根本没法在FireMonkey下搞原生控件,言归正传,查看FMX.Media.Android.pas发现,JViewView是直接放在JNativeLayout上面的(原生布局控件,Delphi实现的),这个布局控件里只能放一个控件,用SetControl方法(1513行),我要放图片原生控件没法放了,所以要先创建一个其它的布局控件,然后再方向JViewView、JImageView,我这里放的在相对布局JRelativeLayout,具体实现:

  FNativeLayout := TJNativeLayout.JavaClass.init(TAndroidHelper.Activity,
    MainActivity.getWindow.getDecorView.getWindowToken);//创建原生控件
  FNativeLayout.setPosition(0, 0);//设置位置
//FNativeLayout.setSize(XXWidth, XXHeight);//在组件大小变化时设置原生控件的Size,参考FMX.Media.Android.pas中的TAndroidVideo.RealignView方法

var
  params: JRelativeLayout_LayoutParams;//布局参数
begin
  FRelativeLayout := TJRelativeLayout.JavaClass.init(TAndroidHelper.Activity);//创建布局控件
  params := TJRelativeLayout_LayoutParams.JavaClass.init(TJViewGroup_LayoutParams.JavaClass.MATCH_PARENT, TJViewGroup_LayoutParams.JavaClass.MATCH_PARENT);//设置为纵横都拉伸到父控件
  FRelativeLayout.setLayoutParams(params);
end;

下一步将相对布局放到原生控件里

FNativeLayout.setControl(FRelativeLayout);//添加到原生控件上

再将其它控件放到相对布局里(相对布局里可以放多个控件)

var
  params: JRelativeLayout_LayoutParams;
begin
  //创建JImageView,并设置宽高,设置为右上对齐
  FImageView := TJImageView.JavaClass.init(TAndroidHelper.Activity);
  params := TJRelativeLayout_LayoutParams.JavaClass.init(W, H);
  params.addRule(TJRelativeLayout.JavaClass.ALIGN_PARENT_TOP);
  params.addRule(TJRelativeLayout.JavaClass.ALIGN_PARENT_RIGHT);
  params.topMargin := 30;
  params.rightMargin := 30;
  FImageView.setLayoutParams(params);
end;

function GetJBitmap(const Bitmap: TBitmap): JBitmap;
var
  Surface: TBitmapSurface;
  JavaBitmap: JBitmap;
begin
  //FireMonkey的Bitmap转成JImageView需要的JBitmap
  Result := nil;
  Surface := TBitmapSurface.Create;
  try
    Surface.Assign(Bitmap);
    JavaBitmap := TJBitmap.JavaClass.createBitmap(Surface.Width, Surface.Height, TJBitmap_Config.JavaClass.ARGB_8888);
    if SurfaceToJBitmap(Surface, JavaBitmap) then
      Result := JavaBitmap;
  finally
    Surface.DisposeOf;
  end;
end;

//使用方法
procedure ShowImage(Bitmap: TBitmap);
var
  bmp: JBitmap;
begin
  bmp := GetJBitmap(Bitmap);
  CallInUIThread(procedure
  begin
    FImageView.setImageBitmap(bmp);
  end);
end;

三、滚动字幕

据说使用JTextView可以实现,写法与JImageView差不多,在单行且文字超出时可以自动滚动,关键是要重载isFocused方法,还有一些简单设定

public class AutoMarqueeTextView extends TextView {
    @Override public boolean isFocused() {
        //这个方法必须返回true,制造假象,当系统调用该方法的时候,会一直以为TextView已经获取了焦点
        return true; 
    }
}

好像无法控制滚动速度,最重要的怎么用delphi来实现这个JAVA类的重载,没搞定啊,谁知道记得给我留言啊,多谢。

最终使用ImageView方式实现了滚动字幕,使用原生的JBitmap、JCanvas、JPaint进行自绘,最后将JBitmap设置到ImageView。

需要注意的是屏幕分辨率与字原生控件布局的影响,在FireMonkey中作用Java接口时以PX像素为单位,会导致在分辨率高的屏幕上图像显得小,跟Scale和DPI无关,Scale是屏幕长宽比,DPI是每英寸上像素点个数,这里说的分辨率是屏幕长宽像素个数,所以设置图像布局时的长宽使用屏幕长宽的百分比最合适,可以保证在其它分辨率的屏幕下显示效果一致。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章