Eine der Funktionen, die Android so besonders macht, ist die Möglichkeit, jeden Aspekt der Benutzererfahrung anzupassen. Als Android Wear zum ersten Mal bei Google I / O 2014 lancierte, stellten viele Entwickler und Benutzer fest, dass dies für Smart Watches nicht zutraf, da die offizielle API zum Erstellen von Zifferblättern auffällig fehlte. Angesichts der Tatsache, dass die Möglichkeit, benutzerdefinierte Uhrgesichter zu erstellen, eine der wichtigsten Anforderungen der Benutzer war, ist es nicht überraschend, dass Entwickler einen Weg gefunden haben, ihre eigenen Uhrgesichter mit einem undokumentierten Hack in Android Wear zu erstellen.
Zum Glück ließ Google alle schnell wissen, dass eine offizielle API auf dem Weg war, und im Dezember 2014 wurde diese API schließlich für die Entwicklungscommunity freigegeben. In diesem Artikel lernen Sie die offizielle Watch Faces API für Android Wear kennen und implementieren ein einfaches digitales Zifferblatt, das Sie für Ihre eigenen Bedürfnisse erweitern können. Die Implementierung von Zifferblättern kann etwas ausführlich sein, die Beispielanwendung für diesen Artikel finden Sie jedoch auf GitHub.
Um ein eigenes Zifferblatt zu erstellen, müssen Sie zunächst Ihr Projekt in Android Studio einrichten. Wählen Sie beim Erstellen Ihres Projekts Telefon und Tablet mit einer Mindest-SDK von API 18 als Android 4.3 ist die niedrigste Version des Betriebssystems, die gebündelte Android Wear-Anwendungen unterstützt. Sie müssen auch das überprüfen Tragen Box mit einem Mindest-SDK von API 21 ausgewählt. Sie können ein Beispiel davon sehen, was Ihr Ziel Android-Geräte Bildschirm sollte aussehen.
Wenn du zu den beiden kommst Aktivität hinzufügen Bildschirme auswählen Keine Aktivität hinzufügen für beide Bildschirme.
Sobald Sie klicken Fertig, Ihre Projektumgebung sollte ein Modul für erstellen Handy, Mobiltelefon und noch einer für tragen.
Android Wear setzt durch den Einsatz von Uhrgesichtern auf WatchFaceService
. In diesem Artikel erstellen Sie eine Erweiterung von CanvasWatchFaceService
Klasse, die eine Implementierung von WatchFaceService
das bietet auch eine Segeltuch
um dein Zifferblatt herauszuziehen. Beginnen Sie mit dem Erstellen einer neuen Java-Klasse unter tragen Modul in Android Studio, das erweitert wird CanvasWatchFaceService
.
Die öffentliche Klasse WatchFaceService erweitert CanvasWatchFaceService
Sobald Sie Ihre Klasse haben, müssen Sie eine innere Klasse erstellen, WatchFaceEngine
in den Quelldateien dieses Artikels erweitert sich das Motor
. Dies ist die Watch-Face-Engine, die Systemereignisse verarbeitet, z. B. das Abschalten des Bildschirms oder das Wechseln in den Umgebungsmodus.
private Klasse WatchFaceEngine erweitert Engine
Wenn Ihr Stubcode für WatchFaceEngine
ist in, geh zurück zur äußeren Klasse und überschreibe die onCreateEngine
Methode, um Ihre neue innere Klasse zurückzugeben. Dadurch wird Ihr Zifferblatt-Service mit dem Code verknüpft, der die Anzeige steuert.
@Override public Engine onCreateEngine () return new WatchFaceEngine ();
Sobald Sie den Bare-Bones-Service zusammengestellt haben, können Sie mit den allgemeinen Aufgaben des Housekeeping fortfahren AndroidManifest Dateien, damit Ihr Dienst von Android Wear erkannt werden kann. Denken Sie daran, dass Ihr aktueller Code noch nichts tut. Wir werden in diese Klasse zurückkehren und den Motor ausarbeiten, nachdem wir einige Projekte im Haushalt gemacht haben.
Öffne das AndroidManifest.xml Datei in der tragen Modul. Oben sollte man bereits eine Zeile sehen, die sagt:
Unter dieser Zeile müssen wir die zwei erforderlichen Berechtigungen für ein Zifferblatt hinzufügen. Diese Anforderung sind:
Sobald Ihre Berechtigungen festgelegt sind, müssen Sie einen Knoten für Ihren Dienst in der Site hinzufügen Anwendung
Knoten mit Erlaubnis zu BIND_WALLPAPER
, ein paar Sätze von Metadaten
mit Referenzbildern Ihres Zifferblatts für den Auswahlbildschirm (in diesem Beispiel verwenden wir nur das Startsymbol) und ein Vorsatzfilter
Um dem System mitzuteilen, dass Ihr Dienst für die Anzeige eines Zifferblatts gedacht ist.
Einmal dein tragen Manifest ist vollständig, müssen Sie die öffnen AndroidManifest.xml Datei in der Handy, Mobiltelefon Modul und fügen Sie die beiden Berechtigungen hinzu, die wir in verwendet haben tragen Modul für PROVIDE_BACKGROUND
und WAKE_LOCK
, weil Android Wear sowohl das erfordert tragen und Handy, Mobiltelefon Module fordern dieselben Berechtigungen für die Installation der Wear-APK auf der Uhr eines Benutzers an. Sobald beide Manifestdateien ausgefüllt sind, können Sie zu zurückkehren CustomWatchFaceService.java um mit der Implementierung des Motors zu beginnen.
Das Motor
Das mit Ihrem Dienst verknüpfte Objekt ist das, was Ihre Uhr antreibt. Er verarbeitet Timer, zeigt Ihre Benutzeroberfläche an, wechselt in den Umgebungsmodus und verlässt Informationen über die Anzeige der physischen Uhr. Kurz gesagt, hier passiert die Magie.
Als erstes sollten Sie eine Reihe von Member-Variablen in Ihre Engine implementieren, um den Gerätestatus, die Timer-Intervalle und die Attribute für Ihre Anzeige zu verfolgen.
// Membervariablen private Typeface WATCH_TEXT_TYPEFACE = Typeface.create (Typeface.SERIF, Typeface.NORMAL); privates statisches Finale int MSG_UPDATE_TIME_ID = 42; private long mUpdateRateMs = 1000; private Zeit mDisplayTime; private Paint mBackgroundColorPaint; private Paint mTextColorPaint; private boolean mHasTimeZoneReceiverBeenRegistered = false; privater boolescher mIsInMuteMode; private boolean mIsLowBitAmbient; private float mXOffset; private float mYOffset; private int mBackgroundColor = Color.parseColor ("schwarz"); private int mTextColor = Color.parseColor ("rot");
Wie Sie sehen, definieren wir das Schrift
dass wir für unsere Digitaluhr Text sowie die Hintergrundfarbe und die Textfarbe der Uhr verwenden. Das Zeit
Objekt wird für verwendet, Sie haben es erraten und verfolgen die aktuelle Gerätezeit. mUpdateRateMs
wird verwendet, um einen Zeitgeber zu steuern, den wir implementieren müssen, um unser Zifferblatt jede Sekunde zu aktualisieren (daher der Wert von 1000 Millisekunden für) mUpdateRateMs
), weil der Standard WatchFaceService
Verfolgt nur die Zeit in Schritten von einer Minute. mXOffset
und mYOffset
sind definiert, sobald der Motor die physische Form der Uhr kennt, so dass unser Zifferblatt gezeichnet werden kann, ohne zu nahe am oberen oder linken Bildschirmrand zu sein oder durch eine abgerundete Ecke abgeschnitten zu sein. Die drei booleschen Werte werden verwendet, um verschiedene Geräte- und Anwendungszustände zu verfolgen.
Das nächste Objekt, das Sie definieren müssen, ist ein Rundfunkempfänger, der sich mit der Situation befasst, in der ein Benutzer möglicherweise unterwegs ist und Zeitzonen ändert. Dieser Receiver löscht einfach die gespeicherte Zeitzone und setzt die Anzeigezeit zurück.
final BroadcastReceiver mTimeZoneBroadcastReceiver = new BroadcastReceiver () @Override public void onReceive (Kontext-Kontext, Absicht), mDisplayTime.clear (intent.getStringExtra ("Zeitzone")); mDisplayTime.setToNow (); ;
Nachdem Sie Ihren Empfänger definiert haben, ist das letzte Objekt, das Sie oben in Ihrem Modul erstellen müssen, a Handler
sorgt dafür, dass Ihre Uhr jede Sekunde aktualisiert wird. Dies ist aufgrund der Einschränkungen von WatchFaceService
oben diskutiert. Wenn Ihr eigenes Zifferblatt nur jede Minute aktualisiert werden muss, können Sie diesen Abschnitt ignorieren.
private final Handler mTimeHandler = new Handler () @Override public void handleMessage (Nachricht msg) switch (msg.what) case MSG_UPDATE_TIME_ID: invalidate (); if (isVisible () &&! isInAmbientMode ()) long currentTimeMillis = System.currentTimeMillis (); long delay = mUpdateRateMs - (currentTimeMillis% mUpdateRateMs); mTimeHandler.sendEmptyMessageDelayed (MSG_UPDATE_TIME_ID, delay); brechen; ;
Die Umsetzung der Handler
ist ziemlich unkompliziert. Es überprüft zuerst die Nachrichten-ID. Wenn es passt MSG_UPDATE_TIME_ID
, Die aktuelle Ansicht wird weiterhin für das Neuzeichnen ungültig gemacht. Nachdem die Ansicht ungültig gemacht wurde, wird die Handler
prüft, ob der Bildschirm sichtbar ist und sich nicht im Umgebungsmodus befindet. Wenn es sichtbar ist, sendet es eine Wiederholungsanfrage eine Sekunde später. Der Grund, warum wir nur die Aktion in wiederholen Handler
Wenn das Zifferblatt sichtbar ist und sich nicht im Umgebungsmodus befindet, kann es einige Sekunden dauern, bis die Batterie aktualisiert wird. Wenn der Benutzer nicht auf den Bildschirm schaut, greifen wir einfach auf den Bildschirm zurück WatchFaceService
Implementierung, die jede Minute aktualisiert.
Jetzt, da Ihre Variablen und Objekte deklariert sind, ist es an der Zeit, das Zifferblatt zu initialisieren. Motor
hat eine onCreate
Eine Methode, die zum Erstellen von Objekten und anderen Aufgaben verwendet werden sollte, die viel Zeit und Batterie benötigen. Sie möchten auch ein paar Flags für die setzen WatchFaceStyle
Hier können Sie steuern, wie das System mit dem Benutzer interagiert, wenn Ihr Zifferblatt aktiv ist.
@Override public void onCreate (Inhaber von SurfaceHolder) super.onCreate (holder); setWatchFaceStyle (neuer WatchFaceStyle.Builder (CustomWatchFaceService.this) .setBackgroundVisibility (WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE) .setCardPeekMode (WatchFaceStyle.PEEK_MODE_VARIABLE). mDisplayTime = neue Zeit (); initBackground (); initDisplayText ();
Für die Beispiel-App verwenden Sie setWatchFaceStyle
Den Hintergrund Ihrer Benachrichtigungskarten festlegen, um kurz anzuzeigen, ob der Kartentyp als unterbrochen eingestellt ist. Sie können den Peek-Modus auch so einstellen, dass Benachrichtigungskarten nur so viel Platz wie nötig beanspruchen.
Schließlich möchten Sie dem System mitteilen, dass es die Standardzeit nicht anzeigen soll, da Sie es selbst anzeigen. Während dies nur einige der verfügbaren Optionen sind, finden Sie noch weitere Informationen in der offiziellen Dokumentation für WatchFaceStyle.Builder
Objekt.
Nach ihrem WatchFaceStyle
eingestellt wurde, können Sie initialisieren mDisplayTime
als neu Zeit
Objekt.
initBackground
und initDisplayText
ordne die beiden zu Farbe
Objekte, die Sie oben in der Engine definiert haben. Der Hintergrund und der Text sind dann in ihrer Farbe festgelegt, und für den Text werden die Schriftart und die Schriftgröße festgelegt. Außerdem wird Anti-Aliasing aktiviert.
private void initBackground () mBackgroundColorPaint = new Paint (); mBackgroundColorPaint.setColor (mBackgroundColor); private void initDisplayText () mTextColorPaint = new Paint (); mTextColorPaint.setColor (mTextColor); mTextColorPaint.setTypeface (WATCH_TEXT_TYPEFACE); mTextColorPaint.setAntiAlias (true); mTextColorPaint.setTextSize (getResources (). getDimension (R.dimen.text_size));
Als nächstes müssen Sie verschiedene Methoden aus dem implementieren Motor
Klasse, die durch Änderungen des Gerätezustands ausgelöst wird. Wir fangen damit an, die onVisibilityChanged
Diese Methode wird aufgerufen, wenn der Benutzer das Zifferblatt versteckt oder zeigt.
@Override public void onVisibilityChanged (boolean visible) super.onVisibilityChanged (visible); if (sichtbar) if (! mHasTimeZoneReceiverBeenRegistered) IntentFilter filter = new IntentFilter (Intent.ACTION_TIMEZONE_CHANGED); CustomWatchFaceService.this.registerReceiver (mTimeZoneBroadcastReceiver, filter); mHasTimeZoneReceiverBeenRegistered = true; mDisplayTime.clear (TimeZone.getDefault (). getID ()); mDisplayTime.setToNow (); else if (mHasTimeZoneReceiverBeenRegistered) CustomWatchFaceService.this.unregisterReceiver (mTimeZoneBroadcastReceiver); mHasTimeZoneReceiverBeenRegistered = false; updateTimer ();
Wenn diese Methode aufgerufen wird, wird geprüft, ob das Zifferblatt sichtbar ist oder nicht. Wenn das Zifferblatt sichtbar ist, sieht es aus, ob das Zifferblatt angezeigt wird Rundfunkempfänger
dass Sie oben definiert haben Motor
ist eingetragen. Wenn nicht, erstellt die Methode eine IntentFilter
für die ACTION_TIMEZONE_CHANGED
Aktion und registriert die Rundfunkempfänger
darauf zu hören.
Wenn das Zifferblatt nicht sichtbar ist, prüft diese Methode, ob das Zifferblatt angezeigt wird Rundfunkempfänger
kann nicht registriert werden. Einmal die Rundfunkempfänger
wurde behandelt, updateTimer
wird aufgerufen, um das Ziffernblatt für ungültig zu erklären und das Ziffernblatt neu zu zeichnen. updateTimer
stoppt alle Handler
ausstehende Aktionen und prüfen, ob weitere gesendet werden sollen.
private void updateTimer () mTimeHandler.removeMessages (MSG_UPDATE_TIME_ID); if (isVisible () &&! isInAmbientMode ()) mTimeHandler.sendEmptyMessage (MSG_UPDATE_TIME_ID);
Wenn Ihr Dienst mit Android Wear verbunden ist, onApplyWindowInsets
wird genannt. Dies wird verwendet, um festzustellen, ob das Gerät, auf dem Ihr Zifferblatt läuft, rund oder eckig ist. Auf diese Weise können Sie Ihr Ziffernblatt an die Hardware anpassen.
Wenn diese Methode in der Beispielanwendung aufgerufen wird, prüft diese Methode einfach die Geräteform und ändert den X-Versatz, der zum Zeichnen des Uhrgesichtes verwendet wird, um sicherzustellen, dass Ihr Uhrgesicht auf dem Gerät sichtbar ist.
@Override public void onApplyWindowInsets (WindowInsets-Insets) super.onApplyWindowInsets (Insets); mYOffset = getResources (). getDimension (R.dimen.y_offset); if (insets.isRound ()) mXOffset = getResources (). getDimension (R.dimen.x_offset_round); else mXOffset = getResources (). getDimension (R.dimen.x_offset_square);
Die nächste Methode, die Sie überschreiben müssen, ist onPropertiesChanged
. Diese Methode wird aufgerufen, wenn die Hardwareeigenschaften für das Wear-Gerät ermittelt werden, z. B. wenn das Gerät den Burn-In-Schutz oder den Low-Bit-Umgebungsmodus unterstützt.
Bei dieser Methode prüfen Sie, ob diese Attribute für das Gerät gelten, auf dem Ihr Zifferblatt läuft, und speichern Sie sie in einer Mitgliedsvariablen, die oben in Ihrem definiert ist Motor
.
@Override public void onPropertiesChanged (Bundle-Eigenschaften) super.onPropertiesChanged (Eigenschaften); if (properties.getBoolean (PROPERTY_BURN_IN_PROTECTION, false)) mIsLowBitAmbient = properties.getBoolean (PROPERTY_LOW_BIT_AMBIENT, false);
Nachdem Sie die anfänglichen Gerätezustände behandelt haben, möchten Sie sie implementieren onAmbientModeChanged
und onInterruptionFilterChanged
. Wie der Name andeutet, onAmbientModeChanged
wird aufgerufen, wenn sich das Gerät im Umgebungsmodus befindet oder nicht.
Wenn sich das Gerät im Umgebungsmodus befindet, sollten Sie die Farbe Ihres Ziffernblatts in Schwarzweiß ändern, um den Akku des Benutzers zu berücksichtigen. Wenn das Gerät aus dem Umgebungsmodus zurückkehrt, können Sie die Farben Ihres Zifferblattes zurücksetzen. Sie sollten auch auf Anti-Aliasing für Geräte achten, die eine Unterstützung für Umgebungen mit geringem Bitbedarf erfordern. Nachdem alle Flag-Variablen festgelegt wurden, können Sie bewirken, dass das Zifferblatt ungültig wird und neu gezeichnet wird. Anschließend können Sie prüfen, ob der 1-Sekunden-Timer starten soll.
@Override public void onAmbientModeChanged (boolean inAmbientMode) super.onAmbientModeChanged (inAmbientMode); if (inAmbientMode) mTextColorPaint.setColor (Color.parseColor ("white")); else mTextColorPaint.setColor (Color.parseColor ("red")); if (mIsLowBitAmbient) mTextColorPaint.setAntiAlias (! inAmbientMode); invalidate (); updateTimer ();
onInterruptionFilterChanged
wird aufgerufen, wenn der Benutzer die Unterbrechungseinstellungen an seinem Wearable manuell ändert. In diesem Fall müssen Sie prüfen, ob das Gerät stummgeschaltet ist, und dann die Benutzeroberfläche entsprechend ändern. In dieser Situation ändern Sie die Transparenz Ihres Zifferblatts, stellen Sie Ihr ein Handler
Aktualisieren Sie nur jede Minute, wenn das Gerät stummgeschaltet ist, und zeichnen Sie dann das Zifferblatt neu.
@Override public void onInterruptionFilterChanged (int interruptionFilter) super.onInterruptionFilterChanged (interruptionFilter); boolean isDeviceMuted = (interruptionFilter == android.support.wearable.watchface.WatchFaceService.INTERRUPTION_FILTER_NONE); if (isDeviceMuted) mUpdateRateMs = TimeUnit.MINUTES.toMillis (1); else mUpdateRateMs = DEFAULT_UPDATE_RATE_MS; if (mIsInMuteMode! = isDeviceMuted) mIsInMuteMode = isDeviceMuted; int alpha = (isDeviceMuted)? 100: 255; mTextColorPaint.setAlpha (alpha); ungültig machen (); updateTimer ();
Wenn sich Ihr Gerät im Umgebungsmodus befindet, wird die Handler
Timer wird deaktiviert. Ihr Zifferblatt kann weiterhin mithilfe der integrierten Uhrzeit jede Minute mit der aktuellen Uhrzeit aktualisiert werden onTimeTick
Methode zum Ungültigmachen der Segeltuch
.
@Override public void onTimeTick () super.onTimeTick (); ungültig machen ();
Sobald alle Ihre Eventualitäten abgedeckt sind, ist es an der Zeit, Ihr Zifferblatt endgültig herauszuziehen. CanvasWatchFaceService
verwendet einen Standard Segeltuch
Objekt, so müssen Sie hinzufügen onDraw
zu deinem Motor
und ziehen Sie Ihr Zifferblatt manuell heraus.
In diesem Tutorial zeichnen wir einfach eine Textdarstellung der Zeit, obwohl Sie Ihre Einstellung ändern könnten onDraw
um ein analoges Zifferblatt problemlos zu unterstützen. In dieser Methode sollten Sie durch Aktualisieren der Uhrzeit überprüfen, ob Sie die korrekte Uhrzeit anzeigen Zeit
Objekt und dann können Sie Ihr Zifferblatt anwenden.
@Override public void onDraw (Leinwand, Rect-Begrenzungen) super.onDraw (Leinwand, Begrenzungen); mDisplayTime.setToNow (); drawBackground (Zeichenfläche, Begrenzungen); drawTimeText (Leinwand);
drawBackground
Färbt den Hintergrund des Wear-Geräts einfarbig.
private void drawBackground (Leinwand, Rect-Begrenzungen) canvas.drawRect (0, 0, bounds.width (), bounds.height (), mBackgroundColorPaint);
drawTimeText
, erstellt jedoch den Zeittext, der mit Hilfe einiger Hilfemethoden angezeigt wird, und wendet ihn dann an der von Ihnen definierten X- und Y-Versatzstelle auf die Leinwand an onApplyWindowInsets
.
private void drawTimeText (Canvas Canvas) String timeText = getHourString () + ":" + String.format ("% 02d", mDisplayTime.minute); if (isInAmbientMode () || mIsInMuteMode) timeText + = (mDisplayTime.hour.) < 12 ) ? "AM" : "PM"; else timeText += String.format( ":%02d", mDisplayTime.second); canvas.drawText( timeText, mXOffset, mYOffset, mTextColorPaint ); private String getHourString() if( mDisplayTime.hour % 12 == 0 ) return "12"; else if( mDisplayTime.hour <= 12 ) return String.valueOf( mDisplayTime.hour ); else return String.valueOf( mDisplayTime.hour - 12 );
Nachdem Sie die Methoden zum Zeichnen Ihres Zifferblatts implementiert haben, sollten Sie mit den Grundkenntnissen ausgestattet sein, die Sie benötigen, um Ihre eigenen Zifferblätter zu erstellen. Das Schöne an Android Wear-Zifferblättern ist, dass dies nur die Oberfläche des Möglichen zerkratzt.
Sie können begleitende Konfigurationsaktivitäten auf der Uhr oder auf dem Telefon hinzufügen Segeltuch
mit einer OpenGL-Implementierung oder leiten Sie Ihre eigene Klasse von ab WatchFaceService
um Ihre Bedürfnisse zu erfüllen.
Fügen Sie hinzu, dass Sie über das Telefon des Benutzers auf andere APIs oder Informationen zugreifen können, und die Möglichkeiten sind endlos. Werden Sie kreativ mit Ihren Zifferblättern und genießen Sie es.