Я Разработчик Appy Weather и с нетерпением жду возможности предоставить своим пользователям возможность постоянно отображать температуру в строке состояния. К сожалению, это не кажется простым, и я даже не уверен, что это возможно (хотя тот факт, что другие приложения допускают это, заставляет меня думать, что так или иначе).
Обратите внимание на следующее:
1) приложение предназначено для Android 8.0 и выше
2) это приложение Xamarin.Android
Используя TextDrawable , мне удалось динамически создать Drawable, который преобразуется в растровое изображение, показывающее текущую температуру, которая принята функцией Notification.Builder SetSmallIcon ():
Notification.Builder builder = new Notification.Builder(context, channelId)
.SetContentText(text)
.SetOngoing(true);
var bld = Android.Ui.TextDrawable.TextDrawable.TextDrwableBuilder.BeginConfig().FontSize(72).UseFont(Typeface.Create("sans-serif-condensed", TypefaceStyle.Normal)).EndConfig();
var drawable = bld.BuildRect(title, Color.Red);
builder.SetSmallIcon(Icon.CreateWithBitmap(Helper_Icon_Droid.drawableToBitmap(drawable)));
Это работает:
Но это не идеально, потому что:
1) размер текста в идеале должен быть максимально возможным в строке состояния, то есть таким же, как
2) доступная ширина означает, что если температура составляет 100 ° + или -10 ° или менее и, возможно, определенные пары двузначных чисел, то она не будет соответствовать и будет обрезана
3) текст будет виден только в том случае, если для фона задан цвет, который не является черным, белым или прозрачным, что не очень хорошо, поскольку для этого важно не иметь сплошной цвет фона
ОБНОВЛЕНИЕ 1
Итак, как прокомментировал Раймо ниже, SetTicker () не является правильным решением. Не то чтобы я обнаружил это, но совет Saamer WindowManager привел к тому, что я надеюсь приблизиться к желаемому результату.
Я добавил следующие разрешения в Манифест:
<uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_PERMISSION" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Я запрашиваю разрешение в рамках своей настройки:
// permissions
public static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE = 5469;
private string[] _permissions =
{
Manifest.Permission.SystemAlertWindow
};
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE)
{
if ( Android.Provider.Settings.CanDrawOverlays(MainApplication.Context) )
{
JobManager.Instance().Scheduler().setJobTemp();
}
}
}
public void checkDrawOverlayPermission()
{
try
{
// check if we already have permission to draw over other apps
// if we don't, we need to get system permission
if ( !Android.Provider.Settings.CanDrawOverlays(MainApplication.Context) )
{
var intent = new Intent(Android.Provider.Settings.ActionManageOverlayPermission, Android.Net.Uri.Parse("package:" + Android.App.Application.Context.PackageName));
StartActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
}
// otherwise, set up the job
else
{
JobManager.Instance().Scheduler().setJobTemp();
}
}
catch (Exception ex)
{
}
}
Меня правильно перенаправили на экран разрешений соответствующих настроек телефона, и когда я предоставлю разрешение и вернусь в Настройки, он запустит метод, показанный ниже, для планирования почасового задания (используя созданный мной метод внутреннего помощника, который работает нормально), когда пользователь отмечает соответствующую настройку, а также помещает ее в строку состояния непосредственно и сразу за пределами задания:
public void setJobTemp()
{
try
{
if (_scheduler.GetPendingJob(Helper_Notification._NOTIFICATION_ID_TEMP) == null)
{
_jobTemp = _context.CreateJobBuilderUsingJobId<Job_Temp>(Helper_Notification._NOTIFICATION_ID_TEMP);
bool success = Helper_Job.ScheduleJob(_context, _jobTemp, 60, 5);
// besides setting the hourly job above, we want to immediately push it out too
Helper_Notification.Push( ViewModel._instance._http.Response.Hourly.Data[ViewModel._instance._http.Response.Hourly._indexStartFrom].Temperature );
}
}
catch (Exception ex)
{
}
}
Это файл макета ресурса Resource.Layout.StatusBar_Temp, который я создал для использования (используя значение заполнителя для TextView в целях тестирования):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/root"
style="@style/LayoutWrap">
<TextView
android:id="@+id/value"
style="@style/TextWrap"
android:text="abc"/>
</LinearLayout>
И, наконец, этот метод используется для отправки обновления в строку состояния:
public static void Push( string text )
{
IWindowManager windowManager = MainApplication.Context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
var temp = LayoutInflater.From(MainApplication.Context).Inflate(Resource.Layout.StatusBar_Temp, null);
var layoutParams = new WindowManagerLayoutParams(1, 1, WindowManagerTypes.ApplicationOverlay, WindowManagerFlags.NotFocusable, Format.Translucent);
layoutParams.Gravity= GravityFlags.Top | GravityFlags.Left;
layoutParams.X = 0;
layoutParams.Y = 0;
windowManager.AddView(temp, layoutParams);
}
Я использую WindowManagerTypes.ApplicationOverlay, потому что другие типы систем, которые, по-видимому, были предложены в прошлом, больше не могут использоваться с версии 8.0 и выше (когда я пробовал их изначально, возникали исключения).
На данный момент, с помощью приведенного выше кода, я не сталкиваюсь ни с какими исключениями, и кажется, что все работает гладко, как при выполнении задания, так и при первоначальном нажатии. Однако есть большая проблема: кажется, что ничего не нарисовано. Что бы это ни стоило, изначально я попытался сделать это путем создания LinearLayout, содержащего TextView программным способом (в отличие от использования существующего макета), но с той же проблемой, когда ничего не было видно.
Есть идеи?