
Android Design Pattern - MVVM (Part 3)
Hello reader,
in this article, I will write about Android application design in Adobe XD and transferring that design to an Android Studio
Before we start, notice that I have changed model class from Main.java to WeatherModel in our ViewModel class.
private MutableLiveData<WeatherModel> weatherModel;
And our model class is now looking like this:
public class WeatherModel {
private String city, temp, weather;
private TimeDate timeDate;
public WeatherModel(String city, String temp, String weather, TimeDate timeDate) {
this.city = city;
double d = Double.valueOf(temp);
int i = (int) Math.rint(d);
this.temp = String.valueOf(i);
this.weather = weather;
this.timeDate = timeDate;
}
}
Also, note that we have not deleted our Model class. The reason we did this is to extract the data that matters to our app. We should also add getters and setters to our new WeatherModel class.
And our TimeDate Model class for formatting Date and Time (adding business logic to a Model class is not the best approach for a robust application):
public class TimeDate {
private String time, date;
public TimeDate() {}
public String getTime() {
return time;
}
public void setTime() {
String timePattern = "HH:mm";
SimpleDateFormat simpleTimeFormat = new SimpleDateFormat(timePattern, Locale.US);
Date timeDate = new Date();
String sTime = simpleTimeFormat.format(timeDate);
this.time = sTime;
}
public String getDate() {
return date;
}
public void setDate() {
String datePattern = "MMMM dd";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern, new Locale("US"));
Date timeDate = new Date();
String date = simpleDateFormat.format(timeDate);
this.date = date;
}
}
Important notice
Our models contain little parts of business logic which is not the very best practice if you have complicated methods. The best thing is to make a medium between Repository and a Model and to put your business logic in. I will cover that part in articles to come.
So let's get started with designing
1. First, we need to download Adobe XD (free) from the official site and follow the installation steps. Adobe XD Download
2. Create a new project and select the desired screen size. I am using iPhone X.
3. Scetch application and make wireframe. Note that I am not a professional designer but design steps should look something like this:
I have used Google fonts because it comes with a free certificate and it's easy to import to Android Studio. You can alter fonts to suits your eye.
4. Now we will transfer the design to our Activity layout. Navigate to res>layout>activity_main.xml and paste code below:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:background="@drawable/background_main">
<Button
android:id="@+id/bt_refresh"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_margin="12dp"
android:layout_marginTop="24dp"
android:background="@drawable/ic_refresh"
app:layout_constraintHorizontal_bias="0.98"
app:layout_constraintLeft_toRightOf="@id/tv_city"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/tv_time"></Button>
<TextView
android:id="@+id/tv_city"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_bold"
android:textColor="@color/white"
android:textSize="18sp"
android:gravity="center"
app:layout_constraintBottom_toTopOf="@id/tv_time"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_light"
android:letterSpacing="-0.08"
android:textColor="@color/white"
android:textSize="64sp"
app:layout_constraintBottom_toBottomOf="@id/tv_temperature"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2" />
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_light"
android:textColor="@color/white"
android:textSize="14sp"
app:layout_constraintBottom_toTopOf="@id/tv_temperature"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_time"
app:layout_constraintVertical_bias="0.0" />
<ImageView
android:id="@+id/image"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/sunny3x8"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.4"
android:contentDescription="weather icon"/>
<TextView
android:id="@+id/tv_temperature"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/raleway_extralight"
android:textColor="@color/white"
android:textSize="50sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/image" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_margin="24dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:gravity="center"
android:background="#20000000">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_margin="6dp">
<TextView
android:id="@+id/tv_forecast_day_frst"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_light"
android:textColor="@color/white"
android:textSize="18sp"
android:text="Thu"/>
<ImageView
android:id="@+id/image_farecast_first"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/sunny3x8"
android:layout_margin="6dp"/>
<TextView
android:id="@+id/tv_forecast_degree_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_light"
android:textColor="@color/white"
android:textSize="16sp"
android:text="12"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_margin="6dp">
<TextView
android:id="@+id/tv_forecast_day_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_light"
android:textColor="@color/white"
android:textSize="18sp"
android:text="Fri"/>
<ImageView
android:id="@+id/image_farecast_second"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/sunny3x8"
android:layout_margin="6dp"/>
<TextView
android:id="@+id/tv_forecast_degree_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_light"
android:textColor="@color/white"
android:textSize="16sp"
android:text="14"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_margin="6dp">
<TextView
android:id="@+id/tv_forecast_day_third"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_light"
android:textColor="@color/white"
android:textSize="18sp"
android:text="Sat"/>
<ImageView
android:id="@+id/image_farecast_third"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/sunny3x8"
android:layout_margin="6dp"/>
<TextView
android:id="@+id/tv_forecast_degree_third"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_light"
android:textColor="@color/white"
android:textSize="16sp"
android:text="23"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_margin="6dp">
<TextView
android:id="@+id/tv_forecast_day_fourth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_light"
android:textColor="@color/white"
android:textSize="18sp"
android:text="Sun"/>
<ImageView
android:id="@+id/image_farecast_fourth"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/sunny3x8"
android:layout_margin="6dp"/>
<TextView
android:id="@+id/tv_forecast_degree_fourth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_light"
android:textColor="@color/white"
android:textSize="16sp"
android:text="11"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_margin="6dp">
<TextView
android:id="@+id/tv_forecast_day_fifth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_light"
android:textColor="@color/white"
android:textSize="18sp"
android:text="Mon"/>
<ImageView
android:id="@+id/image_farecast_fifth"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/sunny3x8"
android:layout_margin="6dp"/>
<TextView
android:id="@+id/tv_forecast_degree_fifth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_light"
android:textColor="@color/white"
android:textSize="16sp"
android:text="9"/>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
I am using Constraint Layout for the main View. You should download resources (background and weather icons) from my GitHub repo and add it to your project.
5. Make View instances in MainActivity
TextView tvTemperature, tvTime, tvCity, tvDate;
ImageView imgWeather;
Button btRefresh;
and in onCreate() method and this:
tvTemperature = findViewById(R.id.tv_temperature);
tvTime = findViewById(R.id.tv_time);
tvCity = findViewById(R.id.tv_city);
tvDate = findViewById(R.id.tv_date);
imgWeather = findViewById(R.id.image);
btRefresh = findViewById(R.id.bt_refresh);
6. Now we can create our ViewModel instance and observe for changes:
WeatherViewModel model = ViewModelProviders.of(this).get(WeatherViewModel.class);
model.getWeather().observe(this, new Observer<WeatherModel>() {
@Override
public void onChanged(@Nullable WeatherModel model) {
//getting the data from ViewModel and passing it to View
tvTemperature.setText(model.getTemp() + (char) 0x00B0);
tvTime.setText(model.getTimeDate().getTime());
tvCity.setText(model.getCity().toUpperCase());
tvDate.setText(model.getTimeDate().getDate());
//setting icon to appropriate
switch (model.getWeather().toLowerCase()){
case "scattered clouds": imgWeather.setImageDrawable(getResources().getDrawable(R.drawable.very_cloudy3x8));
break;
case "broken clouds": imgWeather.setImageDrawable(getResources().getDrawable(R.drawable.very_cloudy3x8));
break;
case "few clouds": imgWeather.setImageDrawable(getResources().getDrawable(R.drawable.cloudy_13x8));
break;
case "light rain": imgWeather.setImageDrawable(getResources().getDrawable(R.drawable.rain3x8));
break;
case "overcast clouds": imgWeather.setImageDrawable(getResources().getDrawable(R.drawable.cloudy_all3x8));
break;
}
Log.d("weather", model.getWeather());
}
});
Conclusion
We've changed our MVVM Architecture a bit to be able to sustain the scalability of our app. Using the constraint layout gave us the wideness of supported devices and our small app is responsive in a vertical position. In articles to come, I will write about a responsive application layout for both horizontal and vertical device positions as well as on phone or on the tablet.
Thank you for reading.