7. Rich and Responsive Layouts (1)


Android Design Principles

  • 새로운 테마
  • 복잡한 뷰를 위한 새로운 위젯
  • 사용자 지정 그림자 및 애니메이션을 위한 새로운 API

보기에도 좋고 그만큼 기능적인 면에서도 우수하며 사용하기 쉬운 앱을 만드는것이다!

사용자는 우리 앱을 30초면 평가를 한다 / 이것은 대부분 시각적인 요소(UI)에 편중되어 있다

  • 세련되고 깔끔한가?
  • 전문적으로 보이는가?
  • 사용하기는 얼마나 쉬운가?

디자인이라는건 개발자가 설명하기 어려운 사항이기도 합니다
하지만 우리는 기본적으로 많이 사용되는 어플리케이션, 내가 자주 사용하는 어플리케이션을 생각해 봅시다

자세한 것은 Google 에서 제시하는 디자인 가이드 라인을 참고해 봅시다

Google Design
Material design
개발자를 위한 머티리얼 디자인


View & ViewGroup

Android UI를 만들기 위해서는 View를 사용합니다
View는 단순하게 직사각형 화면입니다

drawing과 event handling을 처리합니다
Material Design - Components - Buttons

다음 같은 Layouts(ViewGroup) 또한 View 입니다
또한 ViewGroup안에는 View와 ViewGroup 다 포함하는 구조가 가능합니다

View의 width와 height에 따라서 뷰의 크기가 어떻게 변하는지 알수있습니다

gravity = center 로 설정하면 글자가 가운대 정렬 하는 모습을 볼 수 있습니다
layout_gravity = center 로 설정을 하면 뷰가 부모의 정 가운데에 위치하게 됩니다

padding과 layout_margin을 이용해서 뷰를 원하는 곳으로 이동 할 수 있습니다

android:visibility=

  • visible : 보여준다
  • invisible : 안보여준다(공간 차지 O)
  • gone : 안보여준다(공간 차지 x)

앱이 실행되는 동안에 visibility 를 변경할 수 있습니다

View - visibility


우리는 앱을 만들기 위해서 다양한 화면 세팅을 생각하고 Wire Frame부터 생성합니다

최종적으로 컬러, 아이콘, 폰트, 크기와 같은 완벽한 레이아웃에 도달하도록 하는것입니다


연습

다음과 같이 화면의 와이어 프레임을 정하고 항목의 아이템을 설정합니다

정답

list_item_forecast.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:padding="16dp">

<ImageView
android:id="@+id/list_item_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"/>

<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingLeft="16dp">

<TextView
android:id="@+id/list_item_date_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tomorrow"/>

<TextView
android:id="@+id/list_item_forecast_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Clear"/>

</LinearLayout>

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:id="@+id/list_item_high_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="81"/>

<TextView
android:id="@+id/list_item_low_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="68"/>
</LinearLayout>

</LinearLayout>

연습

  • 새로운 list_item_forecast_today.xml 파일을 만들고 다음과 같은 디자인을 완성해 봅시다

정답

list_item_forecast_today.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:padding="16dp">

<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:orientation="vertical">

<TextView
android:id="@+id/list_item_date_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<TextView
android:id="@+id/list_item_high_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<TextView
android:id="@+id/list_item_low_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>

<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:orientation="vertical">

<ImageView
android:id="@+id/list_item_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<TextView
android:id="@+id/list_item_forecast_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>

ForecastAdapter.bindView() 메서드 안에 내용은 주석합니다
실행을 하면 단순한 화면만 반복되어서 나옵니다
아직 Today 에 대한 표시는 안했습니다

다음과 같이 Cursor의 데이터를 View에 Binding 합시다

ForecastAdapter는 CursorAdapter를 상속해서 구현했습니다
CursorAdapter는 abstract class 입니다. 구현해야 할 메서드가 2개면 충분합니다
newView(), bindView()

newView()는 데이터가 들어 있지 않은 새 항목의 레이아웃을 만듭니다
bindView()는 기존의 만들어져있는 레이아웃을 이용하여서 Cursor 데이터를 사용하여 업데이트합니다


연습

  • ForecastAdapter.bindView() 메서드를 완성해 봅시다
  • list_item_forecast.xml 하드 코딩으로 되어있는 내용들 정리 합시다
  • 밑에 2개의 파일 내용을 추가한 뒤에 해보세요

strings.xml

1
2
3
4
5
6
<resources xmlns:xliff="http://schemas.android.com/apk/res-auto">
<!-- 생략 -->
<string name="today">오늘</string>
<string name="tomorrow">내일</string>
<string name="format_full_friendly_date"><xliff:g id="day">%1$s</xliff:g>, <xliff:g id="date">%2$s</xliff:g></string>
</resources>

Utility.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public static final String DATE_FORMAT = "yyyyMMdd";

/**
* Helper method to convert the database representation of the date into something to display
* to users. As classy and polished a user experience as "20140102" is, we can do better.
*
* @param context Context to use for resource localization
* @param dateInMillis The date in milliseconds
* @return a user-friendly representation of the date.
*/
public static String getFriendlyDayString(Context context, long dateInMillis) {
Time time = new Time();
time.setToNow();
long currentTime = System.currentTimeMillis();
int julianDay = Time.getJulianDay(dateInMillis, time.gmtoff);
int currentJulianDay = Time.getJulianDay(currentTime, time.gmtoff);

if (julianDay == currentJulianDay) {
String today = context.getString(R.string.today);
int formatId = R.string.format_full_friendly_date;
return String.format(
context.getString(formatId,
today,
getFormattedMonthDay(context, dateInMillis)));
} else if ( julianDay < currentJulianDay + 7 ) {
return getDayName(context, dateInMillis);
} else {
SimpleDateFormat shortenedDateFormat = new SimpleDateFormat("MMM dd EEE");
return shortenedDateFormat.format(dateInMillis);
}
}

/**
* Given a day, returns just the name to use for that day.
* E.g "today", "tomorrow", "wednesday".
*
* @param context Context to use for resource localization
* @param dateInMillis The date in milliseconds
* @return
*/
public static String getDayName(Context context, long dateInMillis) {
Time t = new Time();
t.setToNow();
int julianDay = Time.getJulianDay(dateInMillis, t.gmtoff);
int currentJulianDay = Time.getJulianDay(System.currentTimeMillis(), t.gmtoff);
if (julianDay == currentJulianDay) {
return context.getString(R.string.today);
} else if ( julianDay == currentJulianDay +1 ) {
return context.getString(R.string.tomorrow);
} else {
Time time = new Time();
time.setToNow();
SimpleDateFormat dayFormat = new SimpleDateFormat("EEEE");
return dayFormat.format(dateInMillis);
}
}

/**
* Converts db date format to the format "Month day", e.g "June 24".
* @param context Context to use for resource localization
* @param dateInMillis The db formatted date string, expected to be of the form specified
* in Utility.DATE_FORMAT
* @return The day in the form of a string formatted "December 6"
*/
public static String getFormattedMonthDay(Context context, long dateInMillis ) {
Time time = new Time();
time.setToNow();
SimpleDateFormat dbDateFormat = new SimpleDateFormat(Utility.DATE_FORMAT);
SimpleDateFormat monthDayFormat = new SimpleDateFormat("MMMM dd");
String monthDayString = monthDayFormat.format(dateInMillis);
return monthDayString;
}

정답

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Override
public void bindView(View view, Context context, Cursor cursor) {
// Read weather icon ID from cursor
int weatherId = cursor.getInt(ForecastFragment.COL_WEATHER_ID);
// Use placeholder image for now
ImageView iconView = (ImageView) view.findViewById(R.id.list_item_icon);
iconView.setImageResource(R.mipmap.ic_launcher);

// Read date from cursor
long dateInMillis = cursor.getLong(ForecastFragment.COL_WEATHER_DATE);
// Find TextView and set formatted date on it
TextView dateView = (TextView) view.findViewById(R.id.list_item_date_textview);
dateView.setText(Utility.getFriendlyDayString(context, dateInMillis));

// Read weather forecast from cursor
String description = cursor.getString(ForecastFragment.COL_WEATHER_DESC);
// Find TextView and set weather forecast on it
TextView descriptionView = (TextView) view.findViewById(R.id.list_item_forecast_textview);
descriptionView.setText(description);

// Read user preference for metric or imperial temperature units
boolean isMetric = Utility.isMetric(context);

// Read high temperature from cursor
double high = cursor.getDouble(ForecastFragment.COL_WEATHER_MAX_TEMP);
TextView highView = (TextView) view.findViewById(R.id.list_item_high_textview);
highView.setText(Utility.formatTemperature(high, isMetric));

// Read low temperature from cursor
double low = cursor.getDouble(ForecastFragment.COL_WEATHER_MIN_TEMP);
TextView lowView = (TextView) view.findViewById(R.id.list_item_low_textview);
lowView.setText(Utility.formatTemperature(low, isMetric));
}

지금은 모든 항목들이 동일한 레이아웃입니다
Today(오늘) 날씨는 레이아웃이 다르게 표시 되어야 합니다

getItemViewType() 이것을 이용해서 다르게 표시 할 수있습니다
getViewTypeCount() 은 총 몇가지 뷰 형태의 레이아웃이 있는지 표시합니다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private static final int VIEW_TYPE_TODAY = 0;
private static final int VIEW_TYPE_FUTURE_DAY = 1;
private static final int VIEW_TYPE_COUNT = 2;

@Override
public int getItemViewType(int position) {
return position == 0 ? VIEW_TYPE_TODAY : VIEW_TYPE_FUTURE_DAY;
}

@Override
public int getViewTypeCount() {
return VIEW_TYPE_COUNT;
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Choose the layout type
int viewType = getItemViewType(cursor.getPosition());
int layoutId = -1;
// TODO: Determine layoutId from viewType
return LayoutInflater.from(context).inflate(layoutId, parent, false);
}

연습

  • newView() 메서드를 완성해 보세요

정답

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
int viewType = getItemViewType(cursor.getPosition());
int layoutId = -1;

switch (viewType) {
case VIEW_TYPE_TODAY:
layoutId = R.layout.list_item_forecast_today;
break;
case VIEW_TYPE_FUTURE_DAY:
layoutId = R.layout.list_item_forecast;
break;
}

return LayoutInflater.from(context).inflate(layoutId, parent, false);
}

bindView() 메서드는 모든 다른 View에 데이터를 설정합니다(Data Binding)
이미 사용 된 적이 있는 View이었다고해도 전체 View에서 다시 한번 찾아서 사용하게 됩니다

매번 findViewById 호출을 제거하기 위해서 ViewHolder를 이용합니다

하나의 레이아웃안에 여러개의 View를 사용하는 경우 레이아웃에서 각 View를 참조하는 멤버 변수를 포함한 ViewHolder를 이용합니다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static class ViewHolder {
public final ImageView iconView;
public final TextView dateView;
public final TextView descriptionView;
public final TextView highTempView;
public final TextView lowTempView;

public ViewHolder(View view) {
iconView = (ImageView) view.findViewById(R.id.list_item_icon);
dateView = (TextView) view.findViewById(R.id.list_item_date_textview);
descriptionView = (TextView) view.findViewById(R.id.list_item_forecast_textview);
highTempView = (TextView) view.findViewById(R.id.list_item_high_textview);
lowTempView = (TextView) view.findViewById(R.id.list_item_low_textview);
}
}
1
2
3
4
5
6
7
8
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// 생략
View view = LayoutInflater.from(context).inflate(layoutId, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
return view;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();

viewHolder.iconView.setImageResource(R.mipmap.ic_launcher);

long dateInMillis = cursor.getLong(ForecastFragment.COL_WEATHER_DATE);
viewHolder.dateView.setText(Utility.getFriendlyDayString(context, dateInMillis));

String description = cursor.getString(ForecastFragment.COL_WEATHER_DESC);
viewHolder.descriptionView.setText(description);

boolean isMetric = Utility.isMetric(context);

double high = cursor.getDouble(ForecastFragment.COL_WEATHER_MAX_TEMP);
viewHolder.highTempView.setText(Utility.formatTemperature(high, isMetric));

double low = cursor.getDouble(ForecastFragment.COL_WEATHER_MIN_TEMP);
viewHolder.lowTempView.setText(Utility.formatTemperature(low, isMetric));
}

실행하면 잘 나오지만 먼가 허전합니다
날씨를 표현할때 표기법에 맞게 표현해주면 더 완벽할꺼같습니다

가장 무난하게 하는 방법은 번역자가 각 언어에 맞게 텍스트 및 매개변수를 재배치할 수 있도록 하는 것입니다
참고 : xliff tag

1
<string name="format_temperature"><xliff:g id="temp">%1.0f</xliff:g>\u00B0</string>
1
return context.getString(R.string.format_temperature, temp);

-7° 같은 표기가 완성 됩니다

MainActivity는 어느정도 했으니 DetailActivity를 해봅시다

날짜, 최고/최저기온, 추가적인 기상정보, 날씨 아이콘, 날씨 예보 등이 되어있습니다


연습

DetailActivity를 구성해봅시다

  • fragment_detail.xml 수정 (스크롤 추가)
  • DetailActivity와 DetailFragment의 분리
  • DetailFragment View 수정

strings.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- Windspeed formats -->
<!-- Wind in mph [CHAR LIMIT=25] -->
<string name="format_wind_mph">
Wind: <xliff:g id="speed">%1$1.0f</xliff:g> mph <xliff:g id="direction">%2$s</xliff:g>
</string>

<!-- Wind in kph [CHAR LIMIT=25] -->
<string name="format_wind_kmh">
Wind: <xliff:g id="speed">%1$1.0f</xliff:g> km/h <xliff:g id="direction">%2$s</xliff:g>
</string>

<!-- Pressure format CHAR LIMIT=25] -->
<string name="format_pressure">Pressure: <xliff:g id="pressure">%1.0f</xliff:g> hPa</string>

<!-- Humidity format CHAR LIMIT=25]-->
<string name="format_humidity">Humidity: <xliff:g id="humidity">%1.0f</xliff:g> %%</string>

Utility.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static String getFormattedWind(Context context, float windSpeed, float degrees) {
int windFormat;
if (Utility.isMetric(context)) {
windFormat = R.string.format_wind_kmh;
} else {
windFormat = R.string.format_wind_mph;
windSpeed = 0.621371192237334f * windSpeed;
}

String direction = "Unknown";
if (degrees >= 337.5 || degrees < 22.5) {
direction = "N";
} else if (degrees >= 22.5 && degrees < 67.5) {
direction = "NE";
} else if (degrees >= 67.5 && degrees < 112.5) {
direction = "E";
} else if (degrees >= 112.5 && degrees < 157.5) {
direction = "SE";
} else if (degrees >= 157.5 && degrees < 202.5) {
direction = "S";
} else if (degrees >= 202.5 && degrees < 247.5) {
direction = "SW";
} else if (degrees >= 247.5 && degrees < 292.5) {
direction = "W";
} else if (degrees >= 292.5 || degrees < 22.5) {
direction = "NW";
}
return String.format(context.getString(windFormat), windSpeed, direction);
}

정답

onLoadFinished()에서 매번 findViewById를 호출하기 때문에 불필요한 행동을 최소화 하기 위해서 변수로 설정합니다


Optimizing Layouts

Nested Layouts을 구성하는 법도 배웠습니다
하지만 복잡한 Layouts을 inflate하면 리소스도 많이 잡아먹고 앱의 성능과 반응성에도 문제가 생길 수 있습니다

다음과 같은 규칙을 염두해 둡시다

  • 좁고 깊은 레이아웃 구조보다는 넓고 얕은 레이아웃 구조가 좋습니다
  • 같은 레벨의 항목을 여러 개 두고 하위 레벨의 항목을 적게 유지하는 것입니다
  • 액티비티 전체 구조에서 Nested View를 10개 이하로 유지합니다
  • 총 80개 이하의 뷰를 사용합니다

Hierarchy Viewer
Optimizing Your UI
Improve Your Code with Lint

HierarchyViewer 를 총해서 Activity와 Application을 볼 수가 있습니다

또한 Android Studio 에는 Lint 라는 도구가 있습니다

Lint는 정적 분석 도구 입니다
레이아웃 접근성 문제, 번역 누락, 하드코딩된 문자열등등에 대해서 표시해줍니다


Responsive Design

이제 와이어 프레임 단계의 레이아웃을 두 화면(MainActivity, DetailActivity)에 적용을 하였습니다

미리 보기 화면에서 테블릿으로 변경해서 보면 너비만 넓어지고 별 차이가 없습니다
상세보기 화면을 같이 보여주거나 리스트를 보여주는 형식을 변경하는게 더 좋을꺼 같습니다

이렇게 하는게 반응형 디자인의 일부입니다

반응형 디자인이란 앱을 디자인할 때 다양한 화면 크기에서 사용될 것을 고려하는 것을 말합니다
이런 디자인은 어떻게 하며 태블릿처럼 큰 화면의 기기를 고려해 만든다는 것은 어떤 의미일까요?

단순하게 늘어진 UI로만 구성하는것이 아니라 크기에 맞게 보여줄 정보의 제공을 변경하는것을 의미합니다

태블릿 앱 품질
Planning for Multiple Touchscreen Sizes

실제로 Application을 개발하다보면 tablets을 지원 안하는 경우가 더 많습니다
하지만 앞으로 우리는 설계를 할 때 반응형 디자인으로 설계하기를 바랍니다

Application을 만들어야 하는데 기기의 종류는 너무나도 많습니다

휴대폰, 7인치 테블릿, 10인치 테블릿 등등 너무 많습니다
우리는 DP, DPI로 분류를 하는것이 더 좋습니다

ldpi mdpi hdpi xhdpi xxhdpi xxxhdpi
~120 ~160 ~240 ~320 ~480 ~640

px로 하는 것이 아니라 dp를 이용해서 어떤 화면의 크기이던 같은 크기의 이미지로 보여 줄 수 있다

dp 단위를 픽셀 단위로 변환
다중 화면 지원 - 구성 예시

Android의 리소스들은 모두 res 폴더 안에 있습니다

런타임시 Android가 적절하게 리소스를 선택하게 됩니다

다중화면지원
Devices and Displays

이미지를 다운받고 우리 프로젝트에 추가하면 됩니다

Assert

다운 받은 폴더를 확인하면 drawable-hdpi와 같은 형태로 되어있습니다
하지만 우리가 사용할때는 R.drawable.{파일이름} 같은 형태로 사용하면 화면 크기에 맞게 Android 에서 찾아줍니다


연습

  • DetailFragment를 수정해서 날씨 아이콘을 표현하세요

Utility.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
* Helper method to provide the icon resource id according to the weather condition id returned
* by the OpenWeatherMap call.
*
* @param weatherId from OpenWeatherMap API response
* @return resource id for the corresponding icon. -1 if no relation is found.
*/
public static int getIconResourceForWeatherCondition(int weatherId) {
// Based on weather code data found at:
// http://openweathermap.org/weather-conditions
if (weatherId >= 200 && weatherId <= 232) {
return R.drawable.ic_storm;
} else if (weatherId >= 300 && weatherId <= 321) {
return R.drawable.ic_light_rain;
} else if (weatherId >= 500 && weatherId <= 504) {
return R.drawable.ic_rain;
} else if (weatherId == 511) {
return R.drawable.ic_snow;
} else if (weatherId >= 520 && weatherId <= 531) {
return R.drawable.ic_rain;
} else if (weatherId >= 600 && weatherId <= 622) {
return R.drawable.ic_snow;
} else if (weatherId >= 701 && weatherId <= 781) {
return R.drawable.ic_fog;
} else if (weatherId == 800) {
return R.drawable.ic_clear;
} else if (weatherId == 801) {
return R.drawable.ic_light_clouds;
} else if (weatherId >= 802 && weatherId <= 804) {
return R.drawable.ic_cloudy;
}
return -1;
}

/**
* Helper method to provide the art resource id according to the weather condition id returned
* by the OpenWeatherMap call.
*
* @param weatherId from OpenWeatherMap API response
* @return resource id for the corresponding image. -1 if no relation is found.
*/
public static int getArtResourceForWeatherCondition(int weatherId) {
// Based on weather code data found at:
// http://openweathermap.org/weather-conditions
if (weatherId >= 200 && weatherId <= 232) {
return R.drawable.art_storm;
} else if (weatherId >= 300 && weatherId <= 321) {
return R.drawable.art_light_rain;
} else if (weatherId >= 500 && weatherId <= 504) {
return R.drawable.art_rain;
} else if (weatherId == 511) {
return R.drawable.art_snow;
} else if (weatherId >= 520 && weatherId <= 531) {
return R.drawable.art_rain;
} else if (weatherId >= 600 && weatherId <= 622) {
return R.drawable.art_snow;
} else if (weatherId >= 701 && weatherId <= 781) {
return R.drawable.art_fog;
} else if (weatherId == 800) {
return R.drawable.art_clear;
} else if (weatherId == 801) {
return R.drawable.art_light_clouds;
} else if (weatherId >= 802 && weatherId <= 804) {
return R.drawable.art_clouds;
}
return -1;
}

정답

1
mIconView.setImageResource(Utility.getArtResourceForWeatherCondition(weatherId));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();

int viewType = getItemViewType(cursor.getPosition());
switch (viewType) {
case VIEW_TYPE_TODAY: {
viewHolder.iconView.setImageResource(Utility.getArtResourceForWeatherCondition(
cursor.getInt(ForecastFragment.COL_WEATHER_CONDITION_ID)));
break;
}
case VIEW_TYPE_FUTURE_DAY: {
viewHolder.iconView.setImageResource(Utility.getIconResourceForWeatherCondition(
cursor.getInt(ForecastFragment.COL_WEATHER_CONDITION_ID)));
break;
}
}
}

Tablets 은 다음과 같이 화면을 설계하게 됩니다

한 화면에 2개의 fragment를 포함합니다
폰에서는 각 각 하나의 화면으로 존재했던 사항들 입니다

Building a Dynamic UI with Fragments

한 화면에서 각각의 Fragment가 통신을 하는 방법을 알아야 합니다
오늘 날씨를 보여주는 부분은 다른 날씨 보여주는 부분과 같은 모양으로 나오게 해야합니다
현재 활성화 되어있는 항목을 표시하는 방법도 필요하게 됩니다