Перейти к содержанию
  • Регистрация

Лидеры


Популярный контент

Показан контент с высокой репутацией за 20.12.2019 в Сообщения

  1. 9 баллов
    У меня в работе два приложения, и оба они не предназначены для Play market, так как имеют ограниченный круг использования, по сути, чисто внутрикорпоративные. Так что нежелательно и выкладывание их и на альтернативные магазины приложений. Автоматически возникает вопрос обновления. Если в первый раз мы можем установить приложение сами при помощи админов, то обновлять их не так просто. А контингент пользователей не справится с "скачайте APK по ссылке, найдите, куда его скачал браузер, и запустите вручную именно последний скачанный, а не какой попало"... Простейший способ - дать приложению скачать свежую копию с сайта и натравить на полученный файл системный инсталлер. Вот только свежие Andoird делать это напрямик запрещают. Нужен filepropvider. Целый день шуровал по мануалам и YT, Вот то что получилось в результате. Если у вас 10.3.3 как у меня, уже можно не вносить <provider>...</provider> в манифест и свой файл file_paths.xml (или как вам его советуют назвать в интернетах) в деплой. Теперь все это делается хоть несколько странно и однобоко, но автоматически, путем установки галочки Secure File Sharing после этого в манифесте автоматически пропишется один из вариантов размещения файлов, которые вы можете найти в интернете. Используется алиас external-path файл, показанный на рисунке, создается автоматически самой делфи. теперь остается отгадать, какой путь реально подставится вместо "." Как показала практика, все пути выглядят не так, как кажется, если исходить из простого здравого смысла. Целый день использования GetHomeDir и других полезных методов TPath завел меня совсем в тупик. Оказалось все проще (?) st:TMemoryStream; OutputDir: JFile; ApkFile: JFile; ApkUri: Jnet_Uri; path, filename: string; ... OutputDir := TAndroidHelper.Context.getExternalCacheDir(); path := JStringToString(OutputDir.getAbsolutePath); filename := path+'/ASDroid2.apk'; ApkFile := TJfile.JavaClass.init( StringToJstring(filename)); FApkUri := TAndroidHelper.JFileToJURI(ApkFile); st.Position := 0; st.SaveToFile(filename); обратите внимание, в provider_paths мы задаем external-paths, а в коде ищем ExternalCacheDir.!!! (For.Unbelievably.Creative.Knowers!) Потом все просто. FApkUri передаем в интент и запускаем итоговый код примерно таков. (скачивание в потоке с использованием небольшого собственного API, но там ничего важного, можно не обращать внимания) procedure TasdSettingsFrame.bDownloadClick(Sender: TObject); begin {$IFDEF ANDROID} bDownload.Enabled := False; DownloadAndRun(); {$ENDIF} end; {$IFDEF ANDROID} procedure TasdSettingsFrame.DownloadAndRun(); begin ttask.Run(procedure var aapi:TasdAPI; st:TMemoryStream; OutputDir: JFile; ApkFile: JFile; ApkUri: Jnet_Uri; path, filename: string; begin st := TMemoryStream.Create; aapi := TasdAPI.Clone(_API); try aapi.OnReceiveData := OnReceiveData; aapi.getApk(st); if aapi.Err.Code=0 then begin OutputDir := TAndroidHelper.Context.getExternalCacheDir(); path := JStringToString(OutputDir.getAbsolutePath); filename := path+'/ASDroid2.apk'; ApkFile := TJfile.JavaClass.init( StringToJstring(filename)); FApkUri := TAndroidHelper.JFileToJURI(ApkFile); st.Position := 0; st.SaveToFile(filename); TThread.Synchronize(nil,procedure begin bDownload.Enabled := true; StartActivity(FApkUri); end); end; finally st.Free; aapi.Free; end; end); end; procedure StartActivity(ApkUri: Jnet_Uri); var Intent: JIntent; begin Intent := TJIntent.Create(); Intent.setAction(TJIntent.JavaClass.ACTION_VIEW); Intent.addFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK or TJIntent.JavaClass.FLAG_ACTIVITY_CLEAR_TOP or TJIntent.JavaClass.FLAG_GRANT_WRITE_URI_PERMISSION or TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION); Intent.setDataAndType(apkuri, StringToJString('application/vnd.android.package-archive')); TAndroidHelper.Activity.startActivity(Intent); end; procedure TasdSettingsFrame.OnReceiveData(const Sender: TObject; AContentLength: Int64; AReadCount: Int64; var Abort: Boolean); begin tthread.Synchronize(nil, procedure begin pb1.Max := AContentLength; pb1.Value := AReadCount; end); end; {$ENDIF} Вопросы остались конечно, почему так странно с каталогами, но выяснять пока нет желания. Работает - не трожь. Всем удачи. UPD. Для того, чтобы системный инсталлер запускался, нужно не забыть отметить еще одну галочку
  2. 6 баллов
    Brovin Yaroslav

    [FGX Native] Релиз!!!

    Поздравляю всех с наступающим новым годом и рад сообщить вам о релизе FGX Native. Это были 3 года плодотворной работы над этим проектом. За это время была проделана колоссальная работа. И еще многое предстоит преодолеть и реализовать. Рад, что успел зарелизить проект до 2020 года. Спасибо всем участника альфа и бета тестирования за оказанную помощь, обратную связь и поддержку. Надеюсь, что вам понравится полученный продукт и с каждым днем он будет лучше и интереснее. Так же рад поделиться, что в моей команде прибыл один разработчик Виктор. Который помог мне подготовить релиз и продолжить трудится со мной над развитием проекта FGX Native. Это позволит делать больше крутых фич и естественно заниматься поддержанием качества продукта. Триал можно скачать здесь: https://forum.fgx-native.com/. Продажа начнется 1 января 2020 года. Всех с новым "безбажным" годом.
  3. 3 балла
    В процессе разработки столкнулся с очень странной ситуацией, корни которой до сих пор неясны, но решение нашлось. Итак. Делфи 10.3.3. Чистое приложение - пустая форма и кнопка. Отлично работает на разных устройствах кроме Samsung Galaxy Tab A (2016). Android 5.1.1 Программа падает, не успев даже загрузиться. Любая. При этом она же, скомпилированная на другом компе, запускается нормально. И даже после изменения SDK/NDK на нем, ничего не падает. LogCat дает крайне странную картину java.lang.IllegalArgumentException: Unable to load native library: /data/app-lib/com.embarcadero.Project1-1/libProject1.so Начинаем экспериментировать с SDK, NDK и т.д. Поставил также хотфиксы для 10.3.3. Сразу скажу, SDK/NDK ставились отдельно через Android studio, не скачивались вместе с Delphi. Не торопитесь бросать чтение на этом месте!)) На другом компе, где все работает, все ставилось точно так же. Короче, очень много комбинаций версий SDK/NDK проверено. Результат такой. При постепенном понижении версии NDK все взлетело при NDK v22. При этом версия SDK видимо такого большого влияния не имеет, потому что этот вариант нормально работает Повторюсь. На других устройствах все работало и на более новых Ndk. Xiaomi Mi Pad4 , Samsung Galaxy Tab A (2019), Xiaomi Redmi 5 и 5Plus Спасибо за участие и помощь в разборе завалов @Andrey Efimov
  4. 3 балла
    В телефоне нет никаких гарантированных аппаратных данных - или по причине китайщины, или по тому что их можно изменить. Если уже вам так хочется "привязаться" к чему то неизменному, то привязывайтесь к телефонному номеру. Хотя и его может не быть. Палец не панацея - у вас нет никаких гарантий что палец принадлежит владельцу персональных данных. 100% дактилоскопических данных пользователя у вас нет, а на этапе "привязки" пальца, телефон уже может быть в руках злоумышленника. У вас не получится сделать идеальную систему с абсолютной системой от дурака. Поэтому я и предложил исходить из того что приложение на телефоне запускает легальных пользователь. Все иное должно описываться в политике конфиденциальности, типа мы чтим закон о ПД, но если вы долбоклюй и отдали телефон и пинкод постороннему, то вы сами пролюбили свою медкарту. И пинкод никак не позволит войти на другом устройстве - пин код сохраняется локально на устройстве, в папке приложения. И если пользователь ввел его верно, то запросы на сервер авторизуются с заранее сохраненного на устройстве токена (guid, куки или что вам больше нравится). Ситуации "А если кто взломает телефон и перенесет какой то файл на другое устройство" вас не должны волновать абсолютно. Вы предоставили пользователю приложение, а задача пользователя - не пролюбить телефон и свои персональные данные. Дополнительно вы прикрываете свою задницу политикой конфиденциальности, где описываете что не обязаны охранять пользователя и его телефон круглые сутки.
  5. 2 балла
    Есть ещё вот такие компоненты: CData Enterprise Connectors
  6. 1 балл
    Yarpda

    Проблема с Андроид 6

    Я тоже долго мучился и не понимал почему некоторые жалуются на то, что приложение не запускается на некоторых устройствах. Вот методом проб и ошибок пришел к такому варианту. Пусть он и корявый, но рабочий! ))
  7. 1 балл
    Сергей Сергеев

    Проблема с Андроид 6

    мой 39 ! есть куда расти еще.. пс. ПОМОГЛО! вместо ааб- апк сборный и андроид 6 заработал из магазина. Похоже дельфи бракованный ааб ( для Андроида 6 ) собирает..
  8. 1 балл
    Yarpda

    Проблема с Андроид 6

    Попробуйте собрать APK из версий для 32 и 64 бит (нужно в деплое на 64 добавить so файл собранного ранее проекта на 32 бит в папку library\lib\armeabi-v7a\ ). Тогда уже устройство локально будет решать какую версию приложения использовать. По крайней мере у меня так сработало.
  9. 1 балл
    Сергей Сергеев

    Проблема с Андроид 6

    Нашел несколько тем на форуме Дельфи ( андр 5 - крах и т.д.) везде спасает даунгрейд ndk ( для 5.1 до 21) сейчас тоже буду подбирать. Форум Дельфи например, также по моему зависит от версии JDK вопрос о том, какие SDL/NDK версии будут работать на Андр 5-10 - без ответа.. пс. поставил NDK - 22 - заработало на 5.1 ( раньше по проводу не работало с NDK 24)
  10. 1 балл
    CyberStorm

    Умирает ли делфи? (С хабра)

    Странно, что никто не обратил внимание на важную для всех делфистов статью на хабре: https://habr.com/ru/post/481534/
  11. 1 балл
    mazayhin

    Логика авторизации по отпечатку пальца

    На форуме была тема про кейстор, с скидывал пример работы с ним (плохенький, но работает) Для входа по пин коду: Генерируйте ключ, ставьте пин на него, храните в кейсторе, гугл вроде как гарантирует неизвлекаемость ключа. Шифруйте данные авторизации и храните их да хоть в загрузках. Без ключа они бесполезны. Далее пытайтесь расшифровать и работать с ними. Не расшифровались-не тот ключ. Нет доступа к ключу-не тот пин. Если следовать закону, то не удивлюсь, что шифрование должно быть ГОСТ..
  12. 1 балл
    slav_z

    Добавить iOS в существующий проект

    хотел бы я сказать, что это можно сделать через IDE, но... откройте файл <project_name>.dproj, идите в самый конец. найдите секцию <Platforms> и добавьте туда что надо. например это может выглядеть так: <Platforms> <Platform value="Android">True</Platform> <Platform value="Android64">True</Platform> <Platform value="iOSDevice32">True</Platform> <Platform value="iOSDevice64">True</Platform> <Platform value="iOSSimulator">True</Platform> <Platform value="OSX32">True</Platform> <Platform value="OSX64">True</Platform> <Platform value="Win32">True</Platform> <Platform value="Win64">True</Platform> </Platforms>
  13. 1 балл
    krapotkin

    Отпечатки пальцев

    Взять в опциях ide search path ту папку, которая подходит, и юзать
  14. 1 балл
    krapotkin

    Отпечатки пальцев

    https://www.winsoft.sk/aauth.htm
  15. 1 балл
    Олег Киреев

    Не работает TModel3D.Loadfromfile

    Здравствуйте. Предлагаю вместо родной 3D библиотеки установить бесплатную GLScene. Ссылок скачиваний море. Я пользуюсь давно. Конечно не идеал но лучше родной. С Уважением. Олег.
  16. 1 балл
    Олег Киреев

    Навигация и хранение данных

    Я делаю так: 1.Создаю файл базы (БД) например для Виндовс Acces (пример моего в приложении). 2.Создаю файл TreeView.dat. 3.Подключаюсь к БД. 4.Создаю нове ветки так: //Ввести ветку procedure TForm_Glavn.SpeedButton_vvod_vetkiClick(Sender: TObject); begin //проверка наличия текста в Едите if Edit_Mame_Vetok.Text = '' then begin MessageDl.MessageDlg('Вы не ввели название ветки!', mtInformation,[mbYes],0); Abort; end; TreeView1.Items. Add (TreeView1. Selected, Edit_Mame_Vetok.Text) ; //база Query_Glav.Insert; Query_Glav.FieldByName('Dat').AsString:=DateToStr(Now); Query_Glav.FieldByName('Imya_vetok').AsString:=Edit_Mame_Vetok.Text; Query_Glav.FieldByName('Opisanie').AsString:=Memo_opisanie.Text; Query_Glav.Post; //сохраняем дерево F := TFileStream.Create(Base+'\Data\TreeView.dat', fmCreate or fmShareCompat); try F.WriteComponent(TreeView1); finally F.Free; end; Edit_Mame_Vetok.Text:=''; end; 5.Создаю подветки так: //Ввести подветку procedure TForm_Glavn.SpeedButton_vvod_podvetkiClick(Sender: TObject); begin if TreeView1.Selected = nil then begin MessageDl.MessageDlg('Вы не выбрали в какой ветке делаем подветку!', mtInformation,[mbYes],0); Exit; //если не выбрана ветка выходим end; //проверка наличия текста в Едите if Edit_Mame_Vetok.Text = '' then begin MessageDl.MessageDlg('Вы не ввели название ветки!', mtInformation,[mbYes],0); Abort; end; TreeView1.Items.AddChild (TreeView1. Selected, Edit_Mame_Vetok.Text); //база Query_Glav.Insert; Query_Glav.FieldByName('Dat').AsString:=DateToStr(Now); Query_Glav.FieldByName('Imya_vetok').AsString:=Edit_Mame_Vetok.Text; Query_Glav.FieldByName('Opisanie').AsString:=Memo_opisanie.Text; Query_Glav.Post; //сохраняем дерево F := TFileStream.Create(Base+'\Data\TreeView.dat', fmCreate or fmShareCompat); try F.WriteComponent(TreeView1); finally F.Free; end; Edit_Mame_Vetok.Text:=''; end; 6.Прикрепляю файл так: // Прикрепить файл procedure TForm_Glavn.SpeedButton_FileClick(Sender: TObject); var IconStream:TMemoryStream; begin if TreeView1.Selected = nil then begin MessageDl.MessageDlg('Вы не выбрали в какой ветке делаем подветку!', mtInformation,[mbYes],0); Exit; //если не выбрана ветка выходим end; OpenDialog1.InitialDir:=Base; if Opendialog1.Execute then begin //заносим файл в потоке SpeedButton_File.Caption:='Подождите......'; Application.ProcessMessages; IconStream:=TMemoryStream.Create; IconStream.LoadFromFile(OpenDialog1.FileName); //становимся в невидимой таблице на указанной модели Query_Glav.Locate('Imya_vetok',Edit_Mame_Vetok.Text,[loPartialKey, loCaseInsensitive]); Query_Glav.Edit; if (ExtractFileExt(Opendialog1.FileName) = '.pdf')then Query_Glav.FieldByName('RashirenieFile').AsInteger:=3; if (ExtractFileExt(Opendialog1.FileName) = '.docx')then Query_Glav.FieldByName('RashirenieFile').AsInteger:=2; if (ExtractFileExt(Opendialog1.FileName) = '.jpg')then Query_Glav.FieldByName('RashirenieFile').AsInteger:=0; if (ExtractFileExt(Opendialog1.FileName) = '.rar')then Query_Glav.FieldByName('RashirenieFile').AsInteger:=1; (Query_Glav.FieldByName('File') as TBlobField).LoadFromStream(IconStream); IconStream.Free; Application.ProcessMessages; MessageDl.MessageDlg('Файл добавлен в базу!', mtInformation,[mbYes],0); SpeedButton_File.Caption:=' Прикрепить файл'; end else MessageDl.MessageDlg('Ошибка ввода!', mtInformation,[mbYes],0); end; 7. Удаляю ветку или подветку так: //Удалить ветку/ подветку procedure TForm_Glavn.SpeedButton_DeleteClick(Sender: TObject); begin if TreeView1.Items.Count = 0 then //проверка наличия веток вообще begin MessageDl.MessageDlg('Так нет же веток!', mtInformation,[mbYes],0); Abort; end; if TreeView1.Selected.HasChildren=True then //проверка наличия подветки begin MessageDl.MessageDlg('Сначала удалите подветку!', mtInformation,[mbYes],0); Image1.Refresh; Abort; end; if TreeView1.Selected.HasChildren=False then //проверка наличия подветки begin SpeedButton_Delete.Caption:='Подождите.....'; Application.ProcessMessages; //становимся в невидимой таблице на указанной ветке Query_Glav.Locate('Imya_vetok',TreeView1.Selected.Text,[loPartialKey, loCaseInsensitive]); if Query_Glav.FieldByName('Imya_vetok').AsString <> '' then Query_Glav.Delete;//удаляем в базе Application.ProcessMessages; TreeView1.Items.Delete(TreeView1.Selected); //удаляем в дереве Application.ProcessMessages; Image1.Refresh; Application.ProcessMessages; SpeedButton_Delete.Caption:=' Удалить ветку/ подветку'; end; //сохраняем дерево F := TFileStream.Create(Base+'\Data\TreeView.dat', fmCreate or fmShareCompat); try F.WriteComponent(TreeView1); finally F.Free; end; Edit_Mame_Vetok.Text:=''; end; 8. Переименовываю ветки так: //Переименовать ветку/ подветку procedure TForm_Glavn.SpeedButton3Click(Sender: TObject); begin //проверка наличия текста в Едите if Edit_Mame_Vetok.Text = '' then begin MessageDl.MessageDlg('Вы не ввели название ветки!', mtInformation,[mbYes],0); Abort; end; //становимся в невидимой таблице на указанной модели Query_Glav.Locate('Imya_vetok',TreeView1.Selected.Text,[loPartialKey, loCaseInsensitive]); TreeView1.Selected.Text:=Edit_Mame_Vetok.Text; //база Query_Glav.Edit; Query_Glav.FieldByName('Dat').AsString:=DateToStr(Now); Query_Glav.FieldByName('Imya_vetok').AsString:=Edit_Mame_Vetok.Text; Query_Glav.FieldByName('Opisanie').AsString:=Memo_opisanie.Text; Query_Glav.Post; //сохраняем дерево F := TFileStream.Create(Base+'\Data\TreeView.dat', fmCreate or fmShareCompat); try F.WriteComponent(TreeView1); finally F.Free; end; Edit_Mame_Vetok.Text:=''; end; 9.Открываю прикреплённый файл так: // Открыть прикреплённый файл отдельно procedure TForm_Glavn.SpeedButton4Click(Sender: TObject); var ImageData:TMemoryStream; begin if TreeView1.Selected = nil then begin MessageDl.MessageDlg('Вы не выбрали в какой ветке делаем подветку!', mtInformation,[mbYes],0); Exit; //если не выбрана ветка выходим end; //становимся в невидимой таблице на указанной модели Query_Glav.Locate('Imya_vetok',Edit_Mame_Vetok.Text,[loPartialKey, loCaseInsensitive]); ImageData:=TMemoryStream.Create; (Query_Glav.FieldByName('File') as TBlobField).SaveToStream(ImageData); ImageData.Position:=0; if ImageData.Size<>0 then begin if Query_Glav.FieldByName('RashirenieFile').AsInteger=3 then Path:=Base+'\Temp\Dokument.pdf'; if Query_Glav.FieldByName('RashirenieFile').AsInteger=2 then Path:=Base+'\Temp\Dokument.docx'; if Query_Glav.FieldByName('RashirenieFile').AsInteger=0 then Path:=Base+'\Temp\Dokument.jpg'; if Query_Glav.FieldByName('RashirenieFile').AsInteger=1 then Path:=Base+'\Temp\Dokument.rar'; ImageData.SaveToFile(Path); ImageData.Free; ImageData:=nil; if FileExists(Path) then begin ShellExecute (0, 'open', pChar(Path), nil, nil, SW_SHOW); end else MessageDl.MessageDlg('Файл'+Path+' в папке Data не найден.', mtInformation,[mbYes],0); end else MessageDl.MessageDlg('В этой ветке документа нет.', mtInformation,[mbYes],0); end;
  17. 1 балл
    HTTPAnalyzer показывает: POST / HTTP/1.1 Connection: Keep-Alive Content-Type: application/x-www-form-urlencoded; charset=utf-8 User-Agent: Embarcadero URI Client/1.0 Host: www.yandex.ru Content-Length: 148 nOwnerOrganizMode=1&cRegNumber=%D1%81-5%2F1&cBegRegDate=22.05.2029&cFIO=%D1%81%D0%B5%D1%80%D0%B3&cDocContent=%D0%B9%D1%86%D1%83qwe%D0%B9%D1%86%D1%83 Обилие %D0 - показывают что уходит UNICODE, а кодирование цифр и английского одним символом указывает что это UTF8... и заголовки этому соответствуют Проблема на клиенте отсутствует... копай сервис
  18. 1 балл
    Я недавно или давно писал по поводу почему компилятор при разном наборе USES увеличивает время компиляции где-то от 4 до 10 раз. То есть проект может компилируются за 10 секунд, а при небольших манипуляциях с USES станет компилироваться 40 секунд и тд. Очень хорошо заметно на большом проекте у меня с 1 минуты 18 секунд выросло время компила до 1 часа 40 минут. Ну хватит предыстории после анализа зависимостей и проверки логов обращения к файловой системе был выяснен интересный факт :) У меня в проекте появился UNIT в котором глобальные методы для так сказать конфигурирования внешнего вида компонентов (компоненты тоже самописные) и получилось следующая ситуация: 1. В UNIT с формой лежит один из визуальных компонентов назовем его TXXX 2. соответственно в первом (interface секции) USES данного модуля прописывается автоматом модуль из зависимостей компонента 3. В нижнем (implementation секции) USES расположен UNIT с глобальными методами (назовем его UNIT XXX) для так сказать конфигурирования его (установка бордера и другой дичи) 4. В этом UNIT XXX (interface секции) USES также прописаны модули этих визуальных компонентов для передачи их в методы как параметры. Так вот из-за такой ошибочной связи время компила увеличивается в разы и по анализу project dependency увеличивается с более менее приемлемых (по времени компиляции) 200 до 500. Из сходя из этого начала рефакторинг всего кода и переводить компоненты на интерфейсы это сокращает project dependency проекта и неплохо так, перевод одного компонента который используется почти везде в проекте на интерфейс сократил с 200 до 190 и время компила начала сокращаться. Сори за много букавок, но может кому будет интересно или кто с толкнулся с такой проблемой. Так же в решении и анализе взаимосвязей помог эксперт MMX.
  19. 1 балл
    полезные ссылки https://android-tools.ru/coding/delimsya-fajlami-v-android-s-pomoshhyu-fileprovider/ https://www.delphiworlds.com/2018/06/targeting-android-8-and-higher-continued/
  20. 1 балл
    От программиста никаких действий не требуется. Система любезно сообщает, что откуда попало не ставит, но вот вам переход прямо на нужную настройку. Переходим, включаем, нажимаем back и продолжаем установку...
  21. 1 балл
    У TMS был компонент готовый https://www.tmssoftware.com/site/tmsfnccloudpack.asp
  22. 1 балл
    Пока не изменились. Сейчас активно ведется работа над подготовкой релиза. Сюда входит ряд работ: Подготовка триал версии библиотеки. Библиотека уже собирается для триала, но остается еще работа по подготовке установщика. Создание EULA Налаживание процесса продажи по подписке. Решение лицензионных вопросов. и другие момент. Но перед тем, как выбирать на чем делать проект я все-таки рекомендую вначале ознакомиться с будущем триалом, чтобы понять о возможностях продукта. Чтобы Ваши ожидания оправдались или не оправдались заранее. Из доп. бонусов в этом месяце еще добавлен новый компонент камера, которая позволяет использовать камеру прямо в вашем приложении с превью и без тормозов. Так же параллельно ведется работа над сканером штрихкодов.
  23. 1 балл
    Демо проект с быстрым списком (его подготовил Андрей Зубов) FastSimpleList.apk
  24. 1 балл
    Привет Всем! vkbdhelper.pas Давно пользовался vkbdhelper'ом, но он был только для андроида. руки добрались и до этого, теперь его можно использовать и на IOS изменения * почистил uses секцию * убрал зависимость от платформ (кросс-платформенный) * добавил глобальную переменную VKOffset VKOffset - расстояние между контролом и клавиатурой для тех случаев когда включены подсказки/автозамена и контрол оказывается под доп. панелькой Не все клавиатуры включают доп. панели в свой размер! Например для IOS нужно всегда прибавлять 30-32 пикселя, панель с кнопкой Done перекрывает контрол {$IFDEF IOS} VKOffset := 31; {$ELSE} VKOffset := 0; // на свой вкус // не знаю как определить размер доп. панельки // когда она не входит в размер клавиатуры // и определить есть ли панелька вообще... {$ENDIF} vkbdhelper.zip
  25. 1 балл
    Вот старое видео. Могу собрать апк. Screenrecorder-2018-11-09-03-12-15-842.mp4
  26. 1 балл
    Как конвертировать растровую картинку в векторный TPath Firemonkey. How to convert a bitmap image (png, jpeg, bmp) into a Firemonkey vector TPath. Manual. Плюсы векторных изображений: Можно изменять размер избражения в любую сторону, уменьшать и увеличивать, без потери качества. Картинка всегда будет с четкими краями, без размытия по краям и квадратиков. Можно легко изменять в RunTime цвет заливки и обводной рамки, изменяя цвета в полях Fill и Stroke компонента TPath. Заливка как правило одна - это цвет из свойства Fill Color. Но ... цвет может быть и градиентом из множества цветов, который можно указать в диспетчере объектов, там же можно загрузить и Bitmap как текстуру в качестве заливки. Можно анимировать изображение, изменяя вышеуказанные свойства, а также направление градиента, размер, толщину обводной линии итд. Тоже можно менять и для Stroke свойства - обводной рамки. Минусы: Получаемое изображение упрощенное. Т.к. оно может содержать только один путь (Path) и одну плоскость. Возможно получиться скомбинировать множества TPath, положив их друг на друга с прозрачностью. Векторное изображение вычисляется и рисуется "в живую", поэтому потребуется больше ресурсов, чем при отрисовке обычных растровых картинок png, jpg, bitmap. Что означает нагрузку на аппаратную часть, замедление работы программы и более быструю разрядку мобильного устройства. Поэтому если и использовать подобные векторные изображения, то в случае если нужно отобразить большие картинки-символы на разных экранах (не иконки) - например на маленьком экране телефона, и на большом планшете и на еще большем Desktop экране. Хотя в примере \Samples\Object Pascal\Multi-Device Samples\User Interface\CustomListBox\CustomListBox.dproj используется векторная иконка\чекбокс очень простая. Преимущества векторного изображения наглядно: Ингредиенты: 1. Векторный редактор, я взял бесплатный inkscape, который можно скачать здесь . 2. Картинка. Желательно чтобы картинка была с большим разрешением, от 300px и больше. Если взять изображение маленького размера, например 48x48 или 64x64, то контуры получатся не такими точными. И хотя inkscape все равно применит сглаживание контуров, и квадратиков вы не увидите, обводные линии могут получиться другой формы, к примеру более жирными или могут слиться с другими линиями. Исходное изображение лучше брать в формате PNG, т.к. JPEG оставляет артефакты в виде точек, в итоге программа при трассировке может захватить и их, что не желательно. Конечно же если другого исходника нету, то смысла конвертировать jpg в png нет - качество не улучшится. Основной метод конвертации - это трассировка изображения, - когда алгоритм ищет края и обводные линии, и на основе их рисует свои. Потому качественные результаты получаться если брать изображение с одной плоскостью, без теней, градиентов и деталей, в стиле Windows 8\10 или Android. Т.н. Flat (плоский) icon. 3. IDE RAD Studio Delphi или С++ Приступим. Запускаем incscape. Размер исходной png картинки 668x720. 1. Меню File > Open - указываем путь. Иконка загрузилась. 2. Нажимаем левой кнопкой мыши на картинку, чтобы она выделилась. 3. Меню Path > Trace Bitmap. Сразу выберите чекбокс Live Preview (см скриншот). Здесь есть разные методы, но нам нужна секция Single Scan: Creates a Path. Методы нужно подбирать визуально, "на глаз". Можно также использовать и секцию Multiply Scans, а затем скомбинировать пути в один (Path > Combine), т.к. нам нужен один путь, и один набор. Путь (Path) это набор инструкций о том как и сколько рисовать линий-векторов. Для нашего конкретного случая, этой конкретной иконки, оптимальный вариант Color Quantization и количество цветов = 2. 4. Нажимаем OK и закрываем окно. Появилось наше изображение залитое черным цветом - это и есть наша векторная картинка. Стоит заметить что прямо под ним лежит наше исходного изображение. Чтобы его удалить нужно отодвинуть мышкой векторное изображение, выделить исходную картинку и удалить ее клавишей Delete. 5. Вы можете отредактировать пути, выбрав в левой панели инструмент Edit Paths By nodes (F2) или добавить фильтры\эффекты в меню Path > Path Effects. В данном примере я ничего не менял. 6. File Save As > inkscape SVG . 7. Открываем полученный SVG файл в блокноте или в Lister тотал коммандера. Ищем массив чисел, который обычно начинается со строчки "<path". Находим эту строчку, нам нужно набор символов, который идет после буквы "d=", к примеру d="m 397.33334,c -48.1 ...-0.326 -1.64129,-0.66405 z" и копируем все, что внутри кавычек в буфер. 8. Далее в RAD IDE кидаем на форму TPath. В Object Inspector WrapMode устанавливаем в Fit, и в поле Data вставляем из буфера наш код. 9. Меняем Fill и Stroke цвета на нужные нам значения (здесь я установил желтый цвет и увеличил толщину обводки (Stroke)). Еще пару примеров. Дерево - параметры Brightness Cutoff, Threshold 0.370 . Как видите здесь оптимальнее подходит метод Brightness Cutoff. Здесь исходная png картинка - это дерево черного цвета, я ее распознал, и затем добавил в TPath, а в свойстве Fill указал градиент от черного до зеленого. Наушники - Edge Detection 0. Конечно конкретно в этом случае нужно подчищать изображение. Иногда бывает что при вставке пути в TPath, компонент его отображает некорректно, если снова зайти в DATA TPath, то окажется что часть данных потеряна. Что исправить эту ситуацию, нужно путь упростить. Это значит что после шага 4, нужно выбрать в incscrape меню Path > Simplify, затем снова сохранить файл. Правда Simplify в incscrape работает не очень хорошо, часто загругляет прямые участки. Лучше делать Simplify в Adobe Illustrator. Статья опубликована на сайте fire-monkey.ru и возможно будет изменяться и дополняться. Автор: ENRGY 24. 02. 17
  27. 1 балл
    Евгений Корепов

    Прочитать DNS запрос в idUDPServer

    Все правильно получаете, кодировка тут не при чем. Согласно спецификации "DNS Packet Structure", вы получаете не строку, а пакет который нужно разобрать. К примеру если запрос будет "nslookup www.google.ru 127.0.0.1", то там где вы получаете имя хоста будет строка "''#3'www'#6'google'#2'ru'#0#0#1#0#1". Парсинг простейший: #3 - означает что далее идут 3 символа хоста 'www' - вот ожидаемые 3 символа #6 - далее идут еще 6 символов хоста 'google' - ага, вот они #2 - ну и еще 2 символа 'ru' - ура, они здесь #0 - конец имени хоста, складываем в кучу, перемежая точками и получаем www.google.ru #0 - дальше у нас служебная информация... #1 #0 #1 Вот как то так. P.S. А зачем вам на таком низком уровне работать? Может использовать IdDNSServer : TIdDNSServer ? P.P.S. Правильно Memo1.Lines.Add(BytesToString(AData,12)); //(12, а не 13)
  28. 1 балл
    ophion

    Диалоговое окно MessageBox на Android

    Используйте MessageDlg. На андроиде немного инная реализация, требующая добавления асинхронной процедуры обрабоки результатов, полученных от MessageDlg. Будет что-то вроде: MessageDlg('Удалить выбранный файл?', TMsgDlgType.mtConfirmation, mbYesNo, 0, procedure (const AResult: TModalResult) begin if (AResult=mrYes) then begin {тут обрабатываете результат нажатия кнопки "Yes"} end; end);
Эта таблица лидеров рассчитана в Москва/GMT+03:00
×
×
  • Создать...