안드로이드 개발 정보
(글 수 1,068)
비슷한 속성을 가지면서 이미지 내의 일부만 변하는 이미지들의 이름은 대부분 [이미지이름]_[이미지번호].[확장자] 형식으로 구성됩니다. 이러한 이미지를 프로젝트 폴더의 리소스 폴더에 넣게 되면 자동으로 R.drawable 클래스에 [이미지이름]_[이미지번호] 라는 이름으로 필드가 생성되고, 각 리소스에 접근할 수 있는 주소가 할당됩니다. 다음은 R.drawable 클래스 내에 선언된 필드의 예를 보여줍니다.
애플리케이션 내에서 이미지 리소스에 접근하려면 R.drawable.[리소스명] 으로 접근하는데, 위의 예시와 같이 이미지 시퀀스가 리소스에 있을 경우 각 이미지에 접근하기 위해 R.drawable.img_0, R.drawable.img_1 ... 등 각 리소스의 이름으로 접근해야 하므로 이미지 번호가 있음에도 불구하고 전체 이미지 이름으로 접근해야 하므로 매우 불편합니다.
이미지가 10개 이내라면 일일이 리소스 이름을 적어도 별 문제가 없겠지만, 이 이상으로 늘어나게 되면 각 리소스를 다루기가 매우 어려워집니다. 리소스가 100개라면 100개의 이름을 하나하나 입력해야 하니, 보통 짜증나는 일이 아니죠.. -_-;;
이러한 불편함을 해결하기 위해, Reflection을 사용하여 R.drawable 클래스 내의 필드 값을 불러오는 방식으로 [이미지이름]+[시퀀스번호] 형태로 구성된 리소스에 접근하는 방법을 알아보겠습니다.
예제 프로젝트:
예제 애플리케이션의 레이아웃은 다음과 같습니다. 이미지 번호를 선택할 수 있는 SeekBar, 현재 시퀀스 번호를 보여주는 TextView, 선택된 이미지를 보여주는 ImageView로 구성되어 있습니다.
[main.xml]
다음, Main 액티비티의 코드를 다음과 같이 작성합니다.
[Main.java]
IMG_NAME_FORMAT에는 이미지 파일의 포맷을 지정합니다. 여기에서는 리소스 이름으로 img_0, img_1 .. 이므로 img_%s로 지정하여 format()메서드를 통해 이미지 번호를 입력받아 최종 이미지 리소스 이름을 만들 수 있도록 하였습니다.
사용자가 SeekBar를 움직였을 때 SeekBar의 위치를 이미지 번호로 받고, 이를 사용하여 이미지 이름을 완성하여 리소스에서 불러오기 위해 format()메서드를 사용하여 완성된 이미지 리소스 이름을 사용하여 해당 필드를 Field 형태로 받고, 필드의 값에는 이미지 리소스에 접근할 주소가 있으므로 setImageResource() 의 인자로 이 값을 넘겨주어 이미지뷰에 해당 리소스를 표시하도록 할 수 있습니다.
애플리케이션을 실행한 모습은 다음과 같습니다. SeekBar의 슬라이더를 움직여 이미지 번호를 선택하면 선택한 이미지가 아래의 ImageView에 표시되는 것을 확인할 수 있습니다.
<script src="http://androidhuman.tistory.com/plugin/CallBack_bootstrapper?&src=http://s1.daumcdn.net/cfs.tistory/v/0/blog/plugins/CallBack/callback&id=495&callbackId=androidhumantistorycom4958249&destDocId=callbacknestandroidhumantistorycom4958249&host=http://androidhuman.tistory.com&float=left&random=265"></script>
public static final class drawable {
public static final int ic_launcher=0x7f020000;
public static final int img_0=0x7f020001;
public static final int img_1=0x7f020002;
public static final int img_2=0x7f020003;
public static final int img_3=0x7f020004;
public static final int img_4=0x7f020005;
public static final int img_5=0x7f020006;
}
애플리케이션 내에서 이미지 리소스에 접근하려면 R.drawable.[리소스명] 으로 접근하는데, 위의 예시와 같이 이미지 시퀀스가 리소스에 있을 경우 각 이미지에 접근하기 위해 R.drawable.img_0, R.drawable.img_1 ... 등 각 리소스의 이름으로 접근해야 하므로 이미지 번호가 있음에도 불구하고 전체 이미지 이름으로 접근해야 하므로 매우 불편합니다.
이미지가 10개 이내라면 일일이 리소스 이름을 적어도 별 문제가 없겠지만, 이 이상으로 늘어나게 되면 각 리소스를 다루기가 매우 어려워집니다. 리소스가 100개라면 100개의 이름을 하나하나 입력해야 하니, 보통 짜증나는 일이 아니죠.. -_-;;
이러한 불편함을 해결하기 위해, Reflection을 사용하여 R.drawable 클래스 내의 필드 값을 불러오는 방식으로 [이미지이름]+[시퀀스번호] 형태로 구성된 리소스에 접근하는 방법을 알아보겠습니다.
[애플리케이션 정보]
액티비티
레이아웃
액티비티
- Main (Main.java)
레이아웃
- main.xml (Main)
예제 애플리케이션의 레이아웃은 다음과 같습니다. 이미지 번호를 선택할 수 있는 SeekBar, 현재 시퀀스 번호를 보여주는 TextView, 선택된 이미지를 보여주는 ImageView로 구성되어 있습니다.
[main.xml]
01.
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
02.
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
03.
android:layout_width
=
"fill_parent"
04.
android:layout_height
=
"fill_parent"
05.
android:orientation
=
"vertical"
android:padding
=
"10dp"
>
06.
07.
<
TextView
08.
android:layout_width
=
"wrap_content"
09.
android:layout_height
=
"wrap_content"
10.
android:text
=
"Image sequence:"
11.
android:textAppearance
=
"?android:attr/textAppearanceMedium"
/>
12.
13.
<
SeekBar
14.
android:id
=
"@+id/imgSeqSeekBar"
15.
android:layout_width
=
"match_parent"
16.
android:layout_height
=
"wrap_content"
android:max
=
"5"
/>
17.
18.
<
TextView
19.
android:id
=
"@+id/imgSeqNum"
20.
android:layout_width
=
"fill_parent"
21.
android:layout_height
=
"wrap_content"
22.
android:text
=
"0"
android:gravity
=
"right"
/>
23.
24.
<
TextView
25.
android:layout_width
=
"wrap_content"
26.
android:layout_height
=
"wrap_content"
27.
android:text
=
"Selected image:"
28.
android:textAppearance
=
"?android:attr/textAppearanceMedium"
/>
29.
30.
<
ImageView
31.
android:id
=
"@+id/imgView"
32.
android:layout_width
=
"match_parent"
33.
android:layout_height
=
"wrap_content"
34.
android:src
=
"@drawable/img_0"
/>
35.
36.
</
LinearLayout
>
다음, Main 액티비티의 코드를 다음과 같이 작성합니다.
[Main.java]
01.
package
com.androidhuman.example.MultipleImageHandling;
02.
03.
import
java.lang.reflect.Field;
04.
05.
import
android.app.Activity;
06.
import
android.os.Bundle;
07.
import
android.widget.ImageView;
08.
import
android.widget.SeekBar;
09.
import
android.widget.SeekBar.OnSeekBarChangeListener;
10.
import
android.widget.TextView;
11.
12.
public
class
Main
extends
Activity {
13.
14.
private
SeekBar sbImgSequence;
15.
private
TextView tvImgSequence;
16.
private
ImageView ivSequenceImage;
17.
18.
private
final
String IMG_NAME_FORMAT =
"img_%s"
;
19.
20.
@Override
21.
public
void
onCreate(Bundle savedInstanceState) {
22.
super
.onCreate(savedInstanceState);
23.
setContentView(R.layout.main);
24.
25.
sbImgSequence = (SeekBar)findViewById(R.id.imgSeqSeekBar);
26.
tvImgSequence = (TextView)findViewById(R.id.imgSeqNum);
27.
ivSequenceImage = (ImageView)findViewById(R.id.imgView);
28.
29.
sbImgSequence.setOnSeekBarChangeListener(
new
OnSeekBarChangeListener(){
30.
31.
@Override
32.
public
void
onProgressChanged(SeekBar seekBar,
int
progress,
33.
boolean
fromUser) {
34.
try
{
35.
// Get resources' Field from R.drawable class
36.
Field drawableRes = R.drawable.
class
.getField(String.format(IMG_NAME_FORMAT, progress));
37.
// Get field's value and set as resource address to be displayed on ImageView
38.
ivSequenceImage.setImageResource(drawableRes.getInt(R.drawable.
class
));
39.
tvImgSequence.setText(String.valueOf(progress));
40.
}
catch
(SecurityException e) {
41.
e.printStackTrace();
42.
}
catch
(NoSuchFieldException e) {
43.
e.printStackTrace();
44.
}
catch
(IllegalArgumentException e) {
45.
e.printStackTrace();
46.
}
catch
(IllegalAccessException e) {
47.
e.printStackTrace();
48.
}
49.
}
50.
51.
@Override
52.
public
void
onStartTrackingTouch(SeekBar seekBar) {
53.
}
54.
55.
@Override
56.
public
void
onStopTrackingTouch(SeekBar seekBar) {
57.
}
58.
59.
});
60.
}
61.
}
사용자가 SeekBar를 움직였을 때 SeekBar의 위치를 이미지 번호로 받고, 이를 사용하여 이미지 이름을 완성하여 리소스에서 불러오기 위해 format()메서드를 사용하여 완성된 이미지 리소스 이름을 사용하여 해당 필드를 Field 형태로 받고, 필드의 값에는 이미지 리소스에 접근할 주소가 있으므로 setImageResource() 의 인자로 이 값을 넘겨주어 이미지뷰에 해당 리소스를 표시하도록 할 수 있습니다.
1.
// Get resources' Field from R.drawable class
2.
Field drawableRes = R.drawable.
class
.getField(String.format(IMG_NAME_FORMAT, progress));
3.
// Get field's value and set as resource address to be displayed on ImageView
4.
ivSequenceImage.setImageResource(drawableRes.getInt(R.drawable.
class
));
5.
tvImgSequence.setText(String.valueOf(progress));
애플리케이션을 실행한 모습은 다음과 같습니다. SeekBar의 슬라이더를 움직여 이미지 번호를 선택하면 선택한 이미지가 아래의 ImageView에 표시되는 것을 확인할 수 있습니다.
<script src="http://androidhuman.tistory.com/plugin/CallBack_bootstrapper?&src=http://s1.daumcdn.net/cfs.tistory/v/0/blog/plugins/CallBack/callback&id=495&callbackId=androidhumantistorycom4958249&destDocId=callbacknestandroidhumantistorycom4958249&host=http://androidhuman.tistory.com&float=left&random=265"></script>
저도 비슷한 방식으로 써본적이 있지만 코드가 조금 틀려 소개해 봅니다.
asset에 json을 넣고 읽는 방식인데요. JSON을 만들어 넣을때 resource ID(int)를 얻을순 없잖아요. 그래서 찾아보니
Resources.getIdentifier 가 있더군요
http://developer.android.com/reference/android/content/res/Resources.html#getIdentifier(java.lang.String, java.lang.String, java.lang.String)
int resId = res.getIdentifier("resfilename", "drawable", "com.com.com");
이렇게 해서 리소스 아이디를 얻은후 JSON에 다시 덮어 씌워서 JSON구조를 직접 사용했습니다. 최초 Init 과정이 필요하지만 편하고 좋아요 :D