web-dev-qa-db-ja.com

Androidアプリの昼/夜のテーマ

昼/夜のテーマを実装する必要があるアプリがあります。残念ながら、スタイルを使用するだけでテーマを作成する簡単な方法はありません。レイアウトの背景、ボタンセレクター、テキストの色、テキストサイズ、画像、アイコン、アニメーションを更新できる必要があります。

私が見るところから、私には2つの選択肢があります。

  1. 夜/日ごとに異なるxmlレイアウトファイルがあるため、home_day.xml/home_night.xmlのようになります。アプリには約30の画面があるため、最終的には60のxmlレイアウトになります。アクティビティ/フラグメントonCreateで、現在の時間に基づいてsetContentViewできます。これにより、xmlファイルがさらに追加されますが、アクティビティにコードが追加されることはありません。

  2. テーマを設定し、現在の昼/夜に基づいて属性を更新するアイテムごとに、昼/夜とアクティビティのonCreatefindviewByIdのレイアウトを1つだけにします。これにより、多くの追加コード、findviewsが生成され、多くのビューに属性が適用される可能性があります。

私は2を目指していますが、あなたからの提案を歓迎します。それで、あなたは何を選びますか、そしてなぜですか?

11
Alin

実際には、テーマを使用してカスタムドローアブルを説明することもできるようです。見てみましょう: Androidでナイトモードとデイモードのテーマを切り替える方法は? 。スタイルブロックを使用してテーマを作成し、xmlレイアウトで?attrを使用してテーマに何かを指定します。次に、次のアクティビティでsetTheme(R.styles.DAY_THEME)を呼び出すことができ、すべてが更新されるはずです。

4
mpellegr

ナイトモードのリソースセット修飾子として-nightを使用し、ナイト固有のリソースをそこに配置します。

Androidにはすでに ナイトモードの概念 があり、時刻とセンサーに基づいてナイトモードとデイタイムモードを切り替えます。したがって、それを使用することを検討するかもしれません。

たとえば、モードに基づいて異なるテーマを設定するには、res/values/styles.xmlres/values-night/styles.xmlを作成します。各ファイルに同じ名前のテーマを設定します(例:AppTheme)が、昼と夜のモードの違いに基づいてテーマを調整します。テーマを名前で参照すると(マニフェストなど)、Androidは適切なリソースに自動的に読み込まれ、Androidは自動的に破棄され、これらのアクティビティの実行中にモードが変更された場合のアクティビティ。

夜をテーマにしたUIを使用するかどうかを手動でユーザーが制御したい場合は、-nightは役に立ちません。

16
CommonsWare

完全なステップバイステップの例については、このチュートリアルを確認してください: ここをクリック

Appcompatv23.2サポートライブラリを使用して自動切り替えDayNightテーマを追加する

_build.gradle_ファイルに次の行を追加します

_compile 'com.Android.support:appcompat-v7:23.2.0'
_

以下のように_styles.xml_でテーマスタイルを作成します

_<resources>
    <!-- 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>
</resources>
_

次に、アプリ全体のテーマを設定するための次のラインコードonCreate()メソッドを追加します。

デフォルトの自動切り替えナイトモードを設定するには、

_AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
_

デフォルトのナイトモードを設定するには

_AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
_

デフォルトの日モードを設定するには

_AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
_

enter image description here

14
nirav kalola

これが私の解決策です:

  • 昼/夜の自動機能が欲しかったのですが、Androidで面倒な車のモードを有効にする必要はありませんでした。

-> NOAAのWebページから、特定の位置と日付を指定して、地平線上の太陽の高さを計算するアルゴリズムを見つけることができます。

->これらのアルゴリズムを使用して、緯度と経度の2つの倍数とカレンダーを指定して地平線上の太陽の高さを計算するメソッドを作成しました

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;
    } 
}

次に、MainActivityに、指定された位置での太陽の高さを5分ごとにチェックするメソッドがあります。

 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();
        }
    }

このメソッドは、使用する現在のスタイルを設定します。私には3つあります。昼と夜に2つ、太陽光が大気中に屈折し始める夕暮れに1つ

<!-- 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>

これはかなりうまく機能しており、夏時間の修正を考慮に入れています。

出典:

NOAAサンライズサンセット

ユリウス日

6
user1892410
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
0
navyarajeevan