Skocz do zawartości
Coders Lab

Zmiana lokalizacji aplikacji

    Rekomendowane odpowiedzi

    Słów kilka na temat lokalizowania aplikacji swojej…

    Fakt, że to czytasz oznacza, że widziałeś na Google Play aplikację, w której można było zmieniać język niezależnie od języka systemu i stwierdziłeś, że coś podobnego zastosujesz u siebie. Pokażę Ci dzisiaj jak to zrobić, ale pragnę zaznaczyć przy tym, że nie jest to dobra praktyka w mojej opinii. Artykuł ten można zaliczyć do grona tutoriali, podzielę go na kroki, które trzeba będzie wykonać, aby zakończyć pracę nad aplikacją. Podejdziemy do tego tutoriala tak samo poważnie jak do każdej innej aplikacji. Do dzieła!


    Cel: Naszym celem jest utworzenie aplikacji, która po kliknięciu na jeden z 4 przycisków wyświetli nam tekst “Dzień dobry!” w języku przypisanym do przycisku.


    Krok 1. Tworzenie projektu aplikacji

    Dobrą praktyką jest wykonywać projekt aplikacji - mnie to motywuje do jej ukończenia + to świetna zabawa i uwielbiam to robić. Ja do tego celu wykorzystuje XD od Adobe.

    • Otwieramy XD i wybieramy nowy projekt dla androida
    • Teraz zobaczysz jak ja wykonałem projekt aplikacji

    2020953415_Zrzutekranu2018-05-19o21_43_39.thumb.png.2fe90c58a199e550bdd75ab447d68ab2.png676584967_Zrzutekranu2018-05-19o21_43_50.thumb.png.96e5c75b46493d912904b8c5123bc6de.png1646875222_Zrzutekranu2018-05-19o21_49_06.thumb.png.f8a2d9ecd99fb04366bf7039e62b760f.png832828962_Zrzutekranu2018-05-19o22_01_44.thumb.png.d19b58ea8ac5d01eba0508e69b725848.png


    Krok 2. Tworzenie aplikacji

    Otwórzmy teraz Android Studio i utwórzmy nowy projekt - ja wybieram Kotlina, Tobie też to polecam.

    • Pierw utworzymy interfejs, który będzie wyrażać naszą potrzebę - czyli zmianę języka. Oto jego kod:
      interface AppLocalization {
      
          fun change(lang: String)
      }

       

    • Utworzymy teraz fragment, który będzie posiadał 4 przyciski (pierwszy ekran z naszego projektu). Oto jego kod:
      class FirstFragment : Fragment() {
      
          companion object {
              fun create() = FirstFragment()
      
              const val TAG = "FirstFragment"
          }
      
          override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                                    savedInstanceState: Bundle?): View? {
              return inflater.inflate(R.layout.fragment_first, container, false)
          }
      
          override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
              val localization = context as AppLocalization
              view.bt_polish.setOnClickListener {
                  localization.change("pl")
              }
      
              view.bt_english.setOnClickListener {
                  localization.change("en")
              }
      
              view.bt_german.setOnClickListener {
                  localization.change("de")
              }
      
              view.bt_italian.setOnClickListener {
                  localization.change("it")
              }
          }
      }
      <?xml version="1.0" encoding="utf-8"?>
      <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          android:layout_width="match_parent"
          android:layout_height="match_parent">
      
      
          <Button
              android:id="@+id/bt_polish"
              style="@style/DiscoButton.Stroke"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@string/button_polish"
              app:layout_constraintBottom_toTopOf="@+id/bt_english"
              app:layout_constraintEnd_toEndOf="parent"
              app:layout_constraintStart_toStartOf="parent"
              app:layout_constraintTop_toTopOf="parent" />
      
          <Button
              android:id="@+id/bt_english"
              style="@style/DiscoButton.Stroke"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_above="@+id/bt_german"
              android:layout_alignParentStart="true"
              android:text="@string/button_english"
              app:layout_constraintBottom_toTopOf="@+id/bt_german"
              app:layout_constraintEnd_toEndOf="parent"
              app:layout_constraintStart_toStartOf="parent"
              app:layout_constraintTop_toBottomOf="@+id/bt_polish" />
      
          <Button
              android:id="@+id/bt_german"
              style="@style/DiscoButton.Stroke"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_alignParentStart="true"
              android:layout_centerVertical="true"
              android:text="@string/button_german"
              app:layout_constraintBottom_toTopOf="@+id/bt_italian"
              app:layout_constraintEnd_toEndOf="parent"
              app:layout_constraintStart_toStartOf="parent"
              app:layout_constraintTop_toBottomOf="@+id/bt_english" />
      
          <Button
              android:id="@+id/bt_italian"
              style="@style/DiscoButton.Stroke"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_alignParentStart="true"
              android:text="@string/button_italian"
              app:layout_constraintBottom_toBottomOf="parent"
              app:layout_constraintEnd_toEndOf="parent"
              app:layout_constraintStart_toStartOf="parent"
              app:layout_constraintTop_toBottomOf="@+id/bt_german" />
      
      
      </android.support.constraint.ConstraintLayout>

       

    • Teraz utworzymy kolejny fragment z jednym TextView na środku, czyli drugi ekran z naszego projektu. Oto jego kod:
       

      class SecondFragment : Fragment() {
      
          companion object {
              fun create() = SecondFragment()
          }
      
          override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                                    savedInstanceState: Bundle?): View? {
              return inflater.inflate(R.layout.fragment_second, container, false)
          }
      }
      <?xml version="1.0" encoding="utf-8"?>
      <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent">
      
      
          <TextView
              android:id="@+id/tv_main_text"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_centerInParent="true"
              android:padding="@dimen/space_mid"
              android:text="@string/label_good_morning"
              android:textSize="@dimen/text_main" />
      
      </RelativeLayout>

      Jak widzisz każdy z przycisków wywołuje tą samą funkcję jednak z innymi parametrami. Jej implementacja znajduje się w MainActivity, którego kod teraz zobaczysz:
       

      class MainActivity : AppCompatActivity(),
              AppLocalization {
      
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_main)
      
              val firstFragment = FirstFragment.create()
      
              if (supportFragmentManager.fragments.count() == 0)
                  supportFragmentManager.beginTransaction()
                          .add(R.id.fl_content, firstFragment, firstFragment.javaClass.name)
                          .setPrimaryNavigationFragment(firstFragment)
                          .commit()
          }
      
          override fun change(lang: String) {
              changeLocalization(this, lang)
              replaceFragment(SecondFragment.create())
          }
      
          private fun changeLocalization(context: Context, lang: String) {
              val myLocale = Locale(lang)
              Locale.setDefault(myLocale)
              val config = android.content.res.Configuration()
              config.locale = myLocale
              context.resources.updateConfiguration(config, context.resources.displayMetrics)
          }
      
          private fun replaceFragment(newFragment: Fragment) {
              val currentFragment: Fragment = supportFragmentManager.findFragmentById(R.id.fl_content)
              val currentFragmentTag: String = currentFragment.javaClass.name
              val newFragmentTag: String = newFragment.javaClass.name
      
              if (currentFragmentTag == newFragmentTag) return
      
              supportFragmentManager.beginTransaction()
                      .replace(R.id.fl_content, newFragment, newFragmentTag)
                      .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
                      .addToBackStack(newFragmentTag)
                      .commit()
          }
      }
      <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical">
      
          <TextView
              android:id="@+id/tv_title"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:background="@color/colorPrimary"
              android:gravity="center_horizontal"
              android:padding="@dimen/space_standard"
              android:text="@string/label_great_app"
              android:textColor="#fff"
              android:textSize="@dimen/button_text_standard" />
      
          <FrameLayout
              android:id="@+id/fl_content"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:layout_above="@id/tv_emoji"
              android:layout_below="@id/tv_title" />
      
          <TextView
              android:id="@+id/tv_emoji"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_alignParentBottom="true"
              android:background="@color/colorPrimary"
              android:gravity="center_horizontal"
              android:padding="@dimen/space_standard"
              android:text="@string/label_emoji"
              android:textColor="#fff"
              android:textSize="@dimen/button_text_standard" />
      
      </RelativeLayout>

       

    Kilka słów na temat kodu, który widzisz powyżej:

    • funkcja changeLocalization

      • przyjmuje jeden parametr, który posłuży nam do zbudowania Locale - w dużym uproszczeniu możesz to rozumieć tak: urządzenie weźmie tekst (string) z katalogu o tej samej nazwie

      • zmienia konfigurację aplikacji na taką, która którą ustawiliśmy w Locale

    • funkcja replaceFragment

      • przyjmuje jeden parametr, którym jest fragment który chcemy otworzyć

      • jeśli będzie to fragment, który już mamy otwarty nic się nie stanie

      • jeśli będzie to nowy fragment, to podmieniamy go, ustawiamy rodzaj przejścia oraz dodajemy go do stosu fragmentów, a na koniec wdrażamy (#popełniamy)

    Dorzucam jeszcze kod "resów" z mojego projektu:

    Style

        <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
        </style>
    
        <style name="DiscoButton.Stroke" parent="Base.Widget.AppCompat.Button">
            <item name="android:background">@drawable/button_ripple_stroke</item>
            <item name="android:textColor">@drawable/button_text_color_stroke</item>
            <item name="android:paddingStart">90dp</item>
            <item name="android:paddingEnd">90dp</item>
        </style>

    Drawable

    <ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="@color/colorPrimaryDark">
        <item>
            <selector>
                <item android:state_pressed="true">
                    <shape
                        android:padding="10dp"
                        android:shape="rectangle">
                        <corners android:radius="10dip" />
                        <solid android:color="@color/colorAccent" />
                    </shape>
                </item>
    
                <item android:state_enabled="true">
                    <shape android:shape="rectangle">
                        <corners android:radius="10dip" />
                        <stroke
                            android:width="2dip"
                            android:color="@color/colorAccent" />
                    </shape>
                </item>
    
                <item android:state_enabled="false">
                    <shape android:shape="rectangle">
                        <corners android:radius="10dip" />
                        <stroke
                            android:width="2dip"
                            android:color="@android:color/darker_gray" />
                    </shape>
                </item>
            </selector>
        </item>
    </ripple>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:color="@android:color/white" android:state_pressed="true" />
        <item android:color="@android:color/darker_gray" android:state_enabled="false" />
        <item android:color="@color/buttonTextColor" android:state_enabled="true" />
    </selector>

    Mam nadzieję, że Wam się podobało i wszystko jest dla Was jasne. Dajcie znać co chcielibyście abym poprawił, by kolejny artykuł był lepszy od tego!

    Na koniec dorzucam jeszcze zrzuty z mojego urządzenia ;)

    3.thumb.jpeg.88467061785d138e5b21a9c50268a145.jpeg2.thumb.jpeg.4dcba26fdcc5131fbb1d71f7322340cf.jpeg1.thumb.jpeg.8f7f809bc9faf8da1d19b0018bf55f20.jpeg

    Specjalnie dla Android.com.pl

    Łukasz Bednarczyk

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach

    Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

    Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

    Zarejestruj nowe konto

    Załóż nowe konto. To bardzo proste!

    Zarejestruj się

    Zaloguj się

    Posiadasz już konto? Zaloguj się poniżej.

    Zaloguj się

    • Przeglądający   0 użytkowników

      Brak zarejestrowanych użytkowników przeglądających tę stronę.