суббота, 4 января 2014 г.

Определяем разрешение и ориентацию экрана/формы

Для решения задачи с определением разрешения воспользуемся JNI (Android API: http://developer.android.com/reference/android/util/DisplayMetrics.html).
На самом деле объяснять тут не чего особо, поэтому я просто приведу код проекта. Не забываем подключить в uses «FMX.Helpers.Android, Androidapi.JNI.Util;». Код, приведённый ниже расписан, чтобы всё было понятно.
Кстати, пример определения ориентации экрана и отображения определённой формы есть в демо проектах Delphi XE5.

Upd (21.04.14). Проверено на Delphi XE6

Код проекта:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
  FMX.Helpers.Android, Androidapi.JNI.Util;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    procedure FormResize(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Disp: JDisplayMetrics;
  NativeClientHeight, NativeClientWidth: Single; // Для формы

implementation

{$R *.fmx}


procedure TForm1.FormResize(Sender: TObject);
begin
  // Общая строчка для экрана и формы
  Disp := GetJDisplayMetrics;

  // Экран
  Label2.Text := 'Width: ' + Disp.widthPixels.ToString();
  Label3.Text := 'Height: ' + Disp.heightPixels.ToString();
  //**********

  // Форма
  NativeClientHeight := ClientHeight * Disp.density;
  NativeClientWidth := ClientWidth * Disp.density;
  Label5.Text := 'Width: ' + FloatToStr(NativeClientWidth);
  Label6.Text := 'Height: ' + FloatToStr(NativeClientHeight);
  //**********

  // Orientation
  if (Height > Width) then
    Label7.Text := 'Orientation: Portrait'
  else if (Height < Width) then
    Label7.Text := 'Orientation: Landscape';
end;

end.


Исходный код проекта: Скачать с Google Drive

14 комментариев:

  1. А почему не пользоваться размерами экрана и формы, который предлагает FM? Например, horizont := Screen.Size.Width > Screen.Size.Height; Штатные компоненты к тому же и в Винде не горят, и на айОсе работают. Какие выгоды мы получили, отказавшись от них?

    ОтветитьУдалить
    Ответы
    1. Не вижу ни чего плохого в использовании JNI для определения разрешения. При написании заметки, стояла цель, получить разрешение (цифры) экрана, при этом, не используя стандартных методов (т.е. использовать API андроида). А для определения ориентации экрана, я не ставил ни каких ограничений по используемым методам. Можно было воспользоваться сервисом IFMXScreenService и определить всё сразу.

      p.s. В блоге, я собираю информацию, относящуюся к разработке под Android. Поэтому JNI было в приоритете.
      p.s.2 Поздравляю с победой в конкурсе. ;)

      Удалить
    2. Сейчас покопался в исходниках и пришёл к выводу, что все способы (хотя могу быть не прав, тут более опытные подскажут) работают через сервис IFMXScreenService, а он в свою очередь через JNI.
      Получается, что нет разницы, каким способом получать ориентацию и разрешение экрана. Однако в случае с использованием JNI или IFMXScreenService всё понятно, а вот с обёртками типа «TScreen.Size» мне не понятно, как получить коэффициент масштабирования, ведь «Screen.Size.Scale» в Delphi нет.

      Удалить
  2. Этот комментарий был удален автором.

    ОтветитьУдалить
  3. Здравствуйте. Скажите,а как сделать форму полностью полноэкранной? Дело в том,что даже при свойстве формы Fullscreen=true панель уведомлений на устройстве остается видимой. Есть ли в Rad Studio способы это исправить?

    ОтветитьУдалить
    Ответы
    1. Заходите в меню "Project->Options->Version Info" меняете "theme" на "No TitleBar"

      Удалить
    2. Решение нашел сам на вашем же сайте. Спасибо,очень полезный сайт.

      Удалить
  4. Ребят помогите! Экран не переворачивается в двух альбомных ориентациях (soLandscape,soInvertedLandscape)
    Я думал так,

    Application.FormFactor.Orientations := [TFormOrientation.soInvertedLandscape,TFormOrientation.soInve rtedLandscape];

    Но экран фиксируется в первом альбомном положении. А мне надо что бы при переворачивании экрана он перевернулся в другое альбомное положение.
    Я заметил что когда отключаю ориентацию Portret, экран фиксируется в одном положении, хотя я ему задаю два.

    Потом я пробывал Project->Option->Application там поставил нужную мне ориетнацию, но тоже не работает.
    Помогите, не знаю что и делать?

    ОтветитьУдалить
    Ответы
    1. Пробывал еще определить как здесь в статье ориентацию,
      if (Height > Width) then
      Application.FormFactor.Orientations := [TFormOrientation.soInvertedLandscape];
      else Application.FormFactor.Orientations[тут все четыре ориентации, т.к. при отключении портретной не работает soInvertedLandscape ]

      Удалить
    2. Все равно иногда бывает портретная ориентация остается

      Удалить
    3. Прочитайте справку http://docwiki.embarcadero.com/RADStudio/XE6/en/Application_Orientation#Notes_about_Orientation_for_Android

      Удалить
  5. Спасибо, почитал и понял, что если я в Project->Option->Application установлю флажки на Landscape home left и Landscape home right, то приложение будет работать только Landscape home left, но как все же сделать так, чтоб оно работал в двух альбомных ориентациях?

    ОтветитьУдалить
  6. Ругается на строчку Disp := GetJDisplayMetrics; в процедуре. Delphi XE7. В программе похоже что-то изменили и теперь подобный код работать отказывается.

    ОтветитьУдалить
    Ответы
    1. Да, к сожалению и я с этим столкнулся.
      Как Вы это обошли?

      Удалить