2013-08-01 19 views
6

Mam aplikację, w której potrzebuję zastosować motyw dzienny/nocny. Niestety nie ma prostego sposobu tworzenia motywów za pomocą tylko stylów, muszę mieć możliwość aktualizacji: tła układu, przycisków, koloru tekstu, rozmiaru tekstu, obrazów, ikon, animacji.Motyw dnia/nocy dla aplikacji na Androida

Z tego co widzę, mam 2 opcje:

  1. mają różne pliki XML szablonu dla noc/dzień, więc coś takiego home_day.xml/home_night.xml. W aplikacji jest około 30 ekranów, więc na końcu pojawi się 60 xml układów. Na aktywność/fragment onCreate, w oparciu o bieżącą godzinę mogłem setContentView. To dodaje trochę więcej plików xml, ale unika dodając więcej kodu w działaniach

  2. mieć tylko jeden układ na dzień/noc oraz na aktywność w onCreate findviewById dla każdego elementu chcę tematu i aktualizować swoje atrybuty na podstawie aktualnego dzień/noc. Może to wygenerować dużo dodatkowego kodu, findviews i zastosować atrybuty dla wielu widoków.

Mam na celu 2., ale jestem otwarty na wszelkie sugestie od ciebie. Więc, co byś wybrał i dlaczego?

+0

użyję '-night' jako zasób ustawionym kwalifikatorem dla trybu nocnego, oddanie specyficzne dla nocy zasoby. – CommonsWare

+0

To naprawdę sprowadza się do tego, czy masz coś przeciwko wykonywaniu GUI w kodzie. Osobiście uważam, że byłoby czystsze i łatwiej mieć oddzielny układ na noc i inny na dzień. Może jednak istnieć trzecia opcja, w której można użyć wyciągnięcia do tła, koloru tekstu i wszystkiego, co powinno się zmienić i utworzyć niestandardowy stan na dzień/noc. Następnie możesz przejrzeć wszystkie swoje poglądy i zmienić stan. Nie wiem, jak bardzo różni się to od twojej opcji 1. – mpellegr

+1

@CommonsCzy mógłbyś nieco rozwinąć odpowiedź? Dzięki – Alin

Odpowiedz

3

Wygląda na to, że można również używać motywów do opisywania niestandardowych rysunków. Spójrz na: How to switch between night-mode and day-mode themes on Android?. Tworzysz motywy za pomocą bloku stylów, a następnie w układzie xml podasz coś w swoim motywie za pomocą? Attr. Wtedy powinieneś móc wywołać setTheme (R.styles.DAY_THEME) przy następnym działaniu i wszystko powinno zostać zaktualizowane.

+0

Problem, który widzę w tym podejściu, na przykład '" Wierzę, że jest częścią tematu, więc mogę go dostosować.Ale co w moim przypadku, gdy potrzebuję na przykład innej opcji do rysowania dla imgLogo? – Alin

+0

To nie są atrybuty systemu Android, są niestandardowe. Musisz zrobić to samemu. Oto dobry przykład: http://stackoverflow.com/questions/3441396/defining-custom-attrs/3441986#3441986. – mpellegr

+0

Na marginesie można również użyć tych niestandardowych atrybutów stylu bezpośrednio w układzie xml. Podobnie jak w przypadku utworzenia atrybutu "exit_button_background", możesz ustawić tę wartość w swoim pliku XML, np. "Myapp: exit_button_background =" @ drawable/night_background "", ale w przypadku Twojego przypadku wydaje się, że musisz utworzyć niestandardowe atrybuty, aby może ich użyć w niestandardowym temacie nocnym i dziennym. – mpellegr

7

Użyłbym -night jako kwalifikatora zestawu zasobów do trybu nocnego, umieszczając w nim twoje nocne zasoby.

Android ma już the notion of night mode, przełączanie trybów nocnych i dziennych w zależności od pory dnia i czujników. Dlatego możesz rozważyć użycie go.

Na przykład, aby mieć inny motyw w oparciu o tryb, utwórz res/values/styles.xml i res/values-night/styles.xml. W każdym pliku znajdź motyw o tej samej nazwie (np. AppTheme), ale dostosuj motyw w oparciu o dowolne różnice między trybem dziennym i nocnym. Gdy powołujesz się na swój motyw po nazwie (np. W manifeście), system Android automatycznie ładuje odpowiednie zasoby, a Android automatycznie niszczy i odtwarza twoje działania, jeśli tryb zmienia się, gdy te czynności są uruchomione.

Teraz, jeśli chcesz ręcznie kontrolować użytkownika, czy używać interfejsu nocnego, -night nie pomoże.

+0

Dzięki za odpowiedź. Muszę być w stanie ustawić kod w chwili pojawienia się motywu nocnego. W lecie może być 22 wieczorem, natomiast w zimie może być 19 wieczorem. Domyślam się więc, że "noc" nie wchodzi w grę, ponieważ ustawienie trybu nocnego mówi "Zmiany trybu nocnego są skuteczne tylko wtedy, gdy tryb samochodowy lub biurkowy jest włączony w urządzeniu." – Alin

+1

@Alin Możesz samodzielnie włączyć tryb samochodowy za pomocą UiModeManager.enableCarMode(), chociaż powiem, że efekty umieszczenia urządzenia w trybie samochodowym nie są dla mnie całkowicie jasne. – spaaarky21

+2

W bibliotece wsparcia 23.2 znajdują się interfejsy API do włączania motywu w aplikacji, który automatycznie przełącza się na noc na podstawie pory dnia. http://android-developers.blogspot.com/2016/02/android-support-library-232.html –

5

tu jest moje rozwiązanie:

  • chciałem mieć automatycznych funkcji dzień/noc, ale nie trzeba włączyć tryb samochodowy kłopotliwe w Androidzie.

-> Ze stron internetowych NOAA można znaleźć algorytmy do obliczania wysokości Słońca nad horyzontem z podaniem określonej pozycji i daty.

-> Używając tych algoritms I stworzył metodę, która oblicza wysokość słońca nad horyzontem podane dwa dwuosobowe Latitude & długość i kalendarz

public class SolarCalculations { 

    /** 
    * Calculate height of the sun above horizon for a given position and date 
    * @param lat Positive to N 
    * @param lon Positive to E 
    * @param cal Calendar containing current time, date, timezone, daylight time savings 
    * @return height of the sun in degrees, positive if above the horizon 
    */ 
    public static double CalculateSunHeight(double lat, double lon, Calendar cal){ 

     double adjustedTimeZone = cal.getTimeZone().getRawOffset()/3600000 + cal.getTimeZone().getDSTSavings()/3600000; 

     double timeOfDay = (cal.get(Calendar.HOUR_OF_DAY) * 3600 + cal.get(Calendar.MINUTE) * 60 + cal.get(Calendar.SECOND))/(double)86400; 

     double julianDay = dateToJulian(cal.getTime()) - adjustedTimeZone/24; 

     double julianCentury = (julianDay-2451545)/36525; 

     double geomMeanLongSun = (280.46646 + julianCentury * (36000.76983 + julianCentury * 0.0003032)) % 360; 

     double geomMeanAnomSun = 357.52911+julianCentury*(35999.05029 - 0.0001537*julianCentury); 

     double eccentEarthOrbit = 0.016708634-julianCentury*(0.000042037+0.0000001267*julianCentury); 

     double sunEqOfCtr = Math.sin(Math.toRadians(geomMeanAnomSun))*(1.914602-julianCentury*(0.004817+0.000014*julianCentury))+Math.sin(Math.toRadians(2*geomMeanAnomSun))*(0.019993-0.000101*julianCentury)+Math.sin(Math.toRadians(3*geomMeanAnomSun))*0.000289; 

     double sunTrueLong = geomMeanLongSun + sunEqOfCtr; 

     double sunAppLong = sunTrueLong-0.00569-0.00478*Math.sin(Math.toRadians(125.04-1934.136*julianCentury)); 

     double meanObliqEcliptic = 23+(26+((21.448-julianCentury*(46.815+julianCentury*(0.00059-julianCentury*0.001813))))/60)/60; 

     double obliqueCorr = meanObliqEcliptic+0.00256*Math.cos(Math.toRadians(125.04-1934.136*julianCentury)); 

     double sunDeclin = Math.toDegrees(Math.asin(Math.sin(Math.toRadians(obliqueCorr))*Math.sin(Math.toRadians(sunAppLong)))); 

     double varY = Math.tan(Math.toRadians(obliqueCorr/2))*Math.tan(Math.toRadians(obliqueCorr/2)); 

     double eqOfTime = 4*Math.toDegrees(varY*Math.sin(2*Math.toRadians(geomMeanLongSun))-2*eccentEarthOrbit*Math.sin(Math.toRadians(geomMeanAnomSun))+4*eccentEarthOrbit*varY*Math.sin(Math.toRadians(geomMeanAnomSun))*Math.cos(2*Math.toRadians(geomMeanLongSun))-0.5*varY*varY*Math.sin(4*Math.toRadians(geomMeanLongSun))-1.25*eccentEarthOrbit*eccentEarthOrbit*Math.sin(2*Math.toRadians(geomMeanAnomSun))); 

     double trueSolarTime = (timeOfDay*1440+eqOfTime+4*lon-60*adjustedTimeZone) % 1440; 

     double hourAngle; 
     if(trueSolarTime/4<0) 
      hourAngle = trueSolarTime/4+180; 
     else 
      hourAngle = trueSolarTime/4-180; 

     double solarZenithAngle = Math.toDegrees(Math.acos(Math.sin(Math.toRadians(lat))*Math.sin(Math.toRadians(sunDeclin))+Math.cos(Math.toRadians(lat))*Math.cos(Math.toRadians(sunDeclin))*Math.cos(Math.toRadians(hourAngle)))); 

     double solarElevation = 90 - solarZenithAngle; 

     double athmosphericRefraction; 
     if(solarElevation>85) 
      athmosphericRefraction = 0; 
     else if(solarElevation>5) 
      athmosphericRefraction = 58.1/Math.tan(Math.toRadians(solarElevation))-0.07/Math.pow(Math.tan(Math.toRadians(solarElevation)),3)+0.000086/Math.pow(Math.tan(Math.toRadians(solarElevation)),5); 
     else if(solarElevation>-0.575) 
      athmosphericRefraction = 1735+solarElevation*(-518.2+solarElevation*(103.4+solarElevation*(-12.79+solarElevation*0.711))); 
     else 
      athmosphericRefraction = -20.772/Math.tan(Math.toRadians(solarElevation)); 
     athmosphericRefraction /= 3600; 

     double solarElevationCorrected = solarElevation + athmosphericRefraction; 

     return solarElevationCorrected; 

    } 


    /** 
    * Return Julian day from date 
    * @param date 
    * @return 
    */ 
    public static double dateToJulian(Date date) { 

     GregorianCalendar calendar = new GregorianCalendar(); 
     calendar.setTime(date); 

     int a = (14-(calendar.get(Calendar.MONTH)+1))/12; 
     int y = calendar.get(Calendar.YEAR) + 4800 - a; 

     int m = (calendar.get(Calendar.MONTH)+1) + 12*a; 
     m -= 3; 

     double jdn = calendar.get(Calendar.DAY_OF_MONTH) + (153.0*m + 2.0)/5.0 + 365.0*y + y/4.0 - y/100.0 + y/400.0 - 32045.0 + calendar.get(Calendar.HOUR_OF_DAY)/24 + calendar.get(Calendar.MINUTE)/1440 + calendar.get(Calendar.SECOND)/86400; 

     return jdn; 
    } 
} 

następnie w główną działalność Mam metodę, która sprawdza co 5 minut na wysokość słońca w danej pozycji:

if(displayMode.equals("auto")){ 
     double sunHeight = SolarCalculations.CalculateSunHeight(lat, lon, cal); 
     if(sunHeight > 0 && mThemeId != R.style.AppTheme_Daylight) 
     {//daylight mode 
      mThemeId = R.style.AppTheme_Daylight; 
      this.recreate(); 
     } 
     else if (sunHeight < 0 && sunHeight >= -6 && mThemeId != R.style.AppTheme_Dusk) 
     {//civil dusk 
      mThemeId = R.style.AppTheme_Dusk; 
      this.recreate(); 
     } 
     else if(sunHeight < -6 && mThemeId != R.style.AppTheme_Night) 
     {//night mode 
      mThemeId = R.style.AppTheme_Night; 
      this.recreate(); 
     } 
    } 

Ta metoda ustawia bieżący styl, a ja mam trzy z nich. Dwie dla dnia i nocy, po jednym dla zmierzchu kiedy słońce zaczyna być załamane do atmosfery

<!-- Application theme. --> 
<style name="AppTheme.Daylight" parent="AppBaseTheme"> 
    <item name="android:background">@color/white</item> 
    <item name="android:panelBackground">@color/gray</item> 
    <item name="android:textColor">@color/black</item> 
</style> 

<style name="AppTheme.Dusk" parent="AppBaseTheme"> 
    <item name="android:background">@color/black</item> 
    <item name="android:panelBackground">@color/gray</item> 
    <item name="android:textColor">@color/salmon</item> 
</style> 

<style name="AppTheme.Night" parent="AppBaseTheme"> 
    <item name="android:background">@color/black</item> 
    <item name="android:panelBackground">@color/gray</item> 
    <item name="android:textColor">@color/red</item> 
</style> 

Zostało pracuje całkiem dobrze i uwzględniać korektę oszczędności czasu letniego.

Źródła:

NOAA Sunrise Sunset

Julian Day

6

Sprawdź ten poradnik dla kompletnej krok po kroku przykład: click here

Dodaj Auto Switching Daynight Theme przy użyciu AppCompat v23.2 bibliotekę wsparcia

Dodaj następującą rzecz w swoim build.gradle złożyć

compile 'com.android.support:appcompat-v7:23.2.0' 

Złóż swój styl rozrywki jak poniżej

<!-- Base application theme. --> 
<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar"> 
    <!-- Customize your theme here. --> 
    <item name="colorPrimary">@color/colorPrimary</item> 
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item> 
    <item name="colorAccent">@color/colorAccent</item> 
    <item name="android:textColorPrimary">@color/textColorPrimary</item> 
    <item name="android:textColorSecondary">@color/textColorSecondary</item> 
</style> 

teraz dodać po jednym kodzie linii w onCreate() metoda ustalania temat dla całej aplikacji

Dla Domyślne ustawienie Automatyczne przełączanie trybu nocnego

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO); 

Dla Domyślne ustawienie Tryb nocny

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); 

Dla ustawieniem domyślnym trybie dziennym

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); 

enter image description here

Powiązane problemy