图片无法在Android设备上正确显示

时间:2019-09-05 00:11:39

标签: android delphi bitmap firemonkey delphi-xe8

我在Android上的FMX出现问题,无法正确显示图像。

我的应用程序是我有史以来第一次使用Android,具有在应用程序启动时显示的背景和启动图像。启动画面显示在所有内容的顶部,然后计时器使它消失,并显示背景。

Memu模拟器的屏幕截图:

image

我手机上的屏幕截图:

image

复制问题的来源:

http://anbech.me/bgtest/bg_test.zip

从Delphi 6开始,我就一直在为Pascal编写代码,在此之前我从未问过任何与编码相关的问题,但这对我来说是很新的。

到目前为止,我已经尝试了3天以使其正常运行,但是没有运气。

当前,我正在使用RCDATA资源并从那里加载图像。我甚至尝试将图像与其他TImage组件放在不同的形式上,然后从那里加载。我还注意到,如果将图像分别设置为Align=ClientWrapMode=Center,则它们都会在MainForm上放错位置,但是在其他形式上效果很好。因此,现在,我尝试裁剪图像,这些图像是正方形的,因此它们的长宽比与其运行的设备相同。

我可以继续,因为到目前为止我已经尝试了很长一段时间。

procedure TForm1.FormShow(Sender: TObject);
var
  Bmp, BmpSplash: TBitmap;
  iRect: TRect;
begin
  Load_image_from_resource(Form1.Image_bg, '0_bg');
  Load_image_from_resource(Form1.Image_splash, '0_splash');

  Bmp := TBitmap.Create;
  try
    Bmp.Width := round(Form1.Image_bg.Bitmap.Width * (Form1.ClientWidth / Form1.ClientHeight));
    Bmp.Height := round(Form1.Image_bg.Bitmap.Height);
    iRect.Width := round(Form1.Image_bg.Bitmap.Width * (Form1.ClientWidth / Form1.ClientHeight));
    iRect.Height := Bmp.Height;
    iRect.Left := round((iRect.Height - iRect.Width) / 2);
    iRect.Top := 0;
    Bmp.CopyFromBitmap(Form1.Image_bg.Bitmap, iRect, 0, 0);
    //Form1.Image_bg.Bitmap := nil;
    Form1.Image_bg.Bitmap.Assign(Bmp);
    Form1.Image_bg.Align := TAlignLayout.Client;
    Form1.Image_bg.WrapMode := TImageWrapMode.Stretch;
  finally
    Bmp.DisposeOf;
    Bmp := nil;
  end;

  BmpSplash := TBitmap.Create;
  try
    BmpSplash.Width := round(Form1.Image_splash.Bitmap.Width * (Form1.ClientWidth / Form1.ClientHeight));
    BmpSplash.Height := round(Form1.Image_splash.Bitmap.Height);
    iRect.Width := round(Form1.Image_splash.Bitmap.Width * (Form1.ClientWidth / Form1.ClientHeight));
    iRect.Height := Bmp.Height;
    iRect.Left := round((iRect.Height - iRect.Width) / 2);
    iRect.Top := 0;
    BmpSplash.CopyFromBitmap(Form1.Image_splash.Bitmap, iRect, 0, 0);
    //Form1.Image_splash.Bitmap := nil;
    Form1.Image_splash.Bitmap.Assign(BmpSplash);
    Form1.Image_splash.Align := TAlignLayout.Client;
    Form1.Image_splash.WrapMode := TImageWrapMode.Stretch;
  finally
    BmpSplash.DisposeOf;
    BmpSplash := nil;
  end;

  Form1.Image_bg.SendToBack;
  Form1.Image_bg.Visible := False;
  Form1.Image_splash.BringToFront;
  Form1.Image_splash.Visible := True;
  Form1.Timer1.Enabled := True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Form1.Timer1.Enabled := False;
  Form1.Image_bg.Visible := True;
  Form1.Image_splash.Visible := False;    
end;

1 个答案:

答案 0 :(得分:0)

您非常亲密,我认为Delphi代码中的以下特性可能会让您最头疼:

在您的代码中,您会有类似的内容:

iRect.Width := ...
iRect.Height := ...
iRect.Left := ...
iRect.Top := ...

TRect(或TRectF)由其四个属性确定:Left, Top, Right, Bottom。 使用width(和height)更改尺寸时,将调用此设置程序:

// This is the code in XE7, I do not know if it has been changed later
procedure TRect.SetWidth(const Value: Integer);
begin
  Self.Right := Self.Left + Value;
end;

SetHeight非常相似。

更改LeftTop时,仅更改了相应的字段,但没有更改RightBottom。结果是widthheight也发生了变化。

想象一下一个本地未初始化的变量iRect,该变量可能具有LeftRight的任何值。上面的代码可能以非常奇怪的TRect矩形结尾。解决方法是先设置LeftTop属性,然后再设置RightTopWidthHeight

要显示图像,您需要使其遵循宽高比,这意味着在垂直显示图像时需要从图像的侧面切开切片(水平显示时必须从顶部和底部切开)。我使用iRect进行了此操作,以便将其初始化为屏幕尺寸,然后使用屏幕尺寸和图像尺寸之间的差值的一半进行补偿。

以下是根据屏幕大小显示图像的代码。这里仅是垂直显示,而水平将遵循相同的方案。为了简洁起见,我也没有包含启动图像,而是使用相同的代码和您自己的更改逻辑。代码中的注释应解释我的观点。如您所见,与iRect.WidthiRect.Left的计算非常相似,这可能是因为TRect的特殊性。

// I feel more comfortable with a bmp as temporary storage than the TImage, therefore this minor mod
procedure Load_Bitmap_From_Resource(var bmp: TBitmap; res_name: String);
var InStream: TResourceStream;
begin
  InStream := TResourceStream.Create(HInstance, res_name, RT_RCDATA);
  try
    Bmp.LoadFromStream(InStream);
  finally
    InStream.Free;
  end;
end;

procedure TForm1.FormShow(Sender: TObject);
var
  ScrHeight, ScrWidth: integer;
  bmp, bmp2, BmpSplash: TBitmap;
  iRect: TRect;
begin
  // Form1 acted for me also as a simulation form during dev, therefore
  // these settings are not meant to be included in actual application
  // ***********
  self.Left := 0; self.ClientWidth  := 270;
  self.Top  := 0; self.ClientHeight := 540;
  // ***********

  // Use FireMonkey Platform Services, IFMXScreeService to get real size of screen
  ScrHeight := 2160; // just arbitrary examples, ..
  ScrWidth  := 1080; // ..for testing use size of your own phone

  // I feel more comfortable with a bmp as temporary storage than the TImage
  bmp := TBitmap.Create;
  try
    Load_Bitmap_From_Resource(bmp, '0_bg');

    iRect := Rect(Point(0, 0), Point(ScrWidth, ScrHeight));
    iRect.Offset((bmp.Width-ScrWidth) div 2, (bmp.Height-ScrHeight) div 2);

    bmp2 := TBitmap.Create;
    try
      bmp2.SetSize(iRect.Width, iRect.Height);
      bmp2.CopyFromBitmap(bmp, iRect, 0, 0);
      Form1.Image_bg.Bitmap.Assign(bmp2);
      Form1.Image_bg.Align := TAlignLayout.Client;
    finally
      bmp2.DisposeOf;
    end;
  finally
    bmp.DisposeOf;
  end;

  Form1.Image_bg.Visible := True;
end;