Android2012. 2. 16. 18:44

개발하면서 많이 쓰는 View 중에 하나가 EditText 입니다. 이번에 개발하던 중에 EditText가 화면의 하단부분에 위치해 있거나 SoftKeyboard의 종류에 따라 사용중인 EditText 의 레이아웃을 가려버리는 일이 생기더군요.

- 설정된 기본 레이아웃입니다.

일부로 EditText의 영역이 SoftKeyboard에 가려질 수 있도록 화면 하단에 배치 했고요.

- 아이디 EditText 에 포커스가 가면서 SoftKeyboard가 올라온 상태입니다.

기본적으로 해당 Activity의 기본 레이아웃이 SoftKeyboard가 올라오면서 살짝 함께 올라가긴 하지만 아이디의 EditText 레이아웃도 가리고 패스워드 EditText의 영역은 보여지지가 않네요.

AnroidManifest.xml 의 해당 Activity에 아래 코드를 입력하면 레이아웃 문제가 해결됩니다.

android:windowSoftInputMode="stateAlwaysHidden|adjustResize"

adjustResize 의 경우가 EditText의 레이아웃을 SoftKeyboard 위로 사이즈를 조정해주고 stateAlwaysHidden 은 처음 Activity가 보여지게 되면서 EditText 에 기본 포커스가 가면서 SoftKeyboard가 보여지는 것을 방지해줍니다.

수정된 레이아웃

'Android' 카테고리의 다른 글

#Android ViewPager  (2) 2012.02.07
#Android Spinner Text Size 및 배열 지정.  (2) 2012.02.04
#Android Device별 기본 UI (Spinner)  (0) 2012.02.03
#Android 이미지 다운로드  (0) 2012.01.19
#Android 파일 다운로드  (0) 2012.01.18
Posted by ™설야
Android2012. 2. 7. 11:18

하나의 Activity에서 여러 가지 레이아웃 페이지를 표현하고자 할 때 많이 사용 하던 것이 ViewFlipper 를 사용해 왔었습니다. 더 나아가 ViewFilpper에 TouchListener를 달아서 좌/우 터치 드래그시에 페이지 전환이 가능하도록 하였고 Animation을 적용시켜 부드럽게 전환되게도 하였죠. 여기에 페이지관리를 편하게 하려고 include도 사용하였었습니다.

오랫동안 안드로이드 개발을 접고 있다가 다시 시작하려고 이것저것 알아 보던 차에 ViewPager란 아주 편리한 컴퍼넌트가 있다는 것을 알게 되었네요. 요놈은 자체적으로 ViewFlipper 사용시에 사용했던 터치 리스너/Animation 등을 자동으로 적용시켜주어서 더 관리가 편해지게끔 만들어 주네요. 거기다 터치 리스너 동작 시에는 다음페이지나 이전페이지로 드래그하다 다시 본래의 페이지로 돌아오게 끔도 할 수 있고요(말로는 설명하기 참 애매하군요 ㅎㅎ) ViewFlipper로 이렇게 작성하기 위해서 예전에 갤러리뷰를 이용한 방법이 있다 들은 것 같은데 이제 ViewPager 하나로 그런 것 다 필요 없어졌네요.

 

ViewPagerTest 구동 영상

위의 동영상은 ViewPagerTest를 구동시킨 영상입니다. 녹화하면서 마우스 커서를 없애버려서 좌/우 버튼을 이용하는지 드래그를 이용하는지 확인이 어려워졌네요!

우선 이클립스에서 안드로이드 프로젝트를 생성하고 ViewPager를 사용하기 위해선 추가 라이브러리를 등록 하셔야 합니다.

android-support-v4.jar는 안드로이드 SDK폴더/extras/android/support/v4 안에 있습니다.

<android.support.v4.view.ViewPager
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:layout_below="@id/bt_prev"
    android:layout_marginTop="15dip" 
    android:id="@+id/vp_main"/>

ViewPager의 xml 기본 사용방법입니다. CustomView들을 만들고 사용하던 것처럼 라이브러리에 저장된 경로 전체로 사용해 주어야 하네요.

cpa = new CustomPagerAdapter();
vp_main = (ViewPager) findViewById(R.id.vp_main);
vp_main.setAdapter(cpa);

CustomPagerAdapter를 ViewPager에 등록하여 사용하였습니다. CustomPagerAdapter는 PagerAdapter를 extends 해주고 내부에서 ViewPager의 크기와 각 페이지에 대한 정의를 해줄 수 있습니다.

//CustomPagerAdapter
//ViewPager 크기 정의
@Override
public int getCount() {
        return VIEW_PAGE_NUM;
}
/**
 * CstomPagerAdapter
 * 각 페이지 정의
 */
@Override
public Object instantiateItem(View collection, int position) {
    View view = null;
    
    if(position == 0){
        view = View.inflate(context, R.layout.page_one, null);
    }else if(position == 1){
        view = View.inflate(context, R.layout.page_two, null);
    }else if(position == 2){
        view = View.inflate(context, R.layout.page_three, null);
    }
    ((ViewPager) collection).addView(view,position);
    
    return view;
}

오러라이드 되는 instantiateItem 에서 각 페이지별로 레이아웃 view들을 정의해 주어 표현합니다. test소스에서는 각 페이지별로 layout xml을 만들어 주었습니다.

//ViewPage 페이지 변경 리스너
vp_main.setOnPageChangeListener(new OnPageChangeListener(){
 
    @Override
    public void onPageScrollStateChanged(int state) {}
 
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
 
    @Override
    public void onPageSelected(int position) {
        //페이지가 변경될때 변경되는 페이지 포지션에 대한 체크(버튼을 활성화/비활성화 시켜줌)
        pageCheck(position);                
    }
    
});

ViewPager 페이지 변경 리스너로 변경 될 때 필요한 사항도 정의를 해줄 수 있습니다. 이번 test소스에서는 좌/우 드래그 뿐만 아니라 임의로 상단에 이전/다음 버튼을 정의하여 그 버튼들에 의해서 변경될 때를 체크하기 위해서 사용하였습니다. 맨 첫번째 페이지에 있으면 이전 버튼의 비활성화 , 마지막 페이지에 있으면 다음 버튼의 비활성화가 리스너에서 해주는 일입니다.

 

Posted by ™설야
Android2012. 2. 4. 08:23

Spinner 컴퍼넌트는 xml을 이용하여 height 사이즈를 변경 시킬 수 있는데 어느 정도 줄이다 보면 글자 크기가 너무 커서 글자가 잘리는 경우가 생기더군요. 이럴 경우엔 TextView 레이아웃을 만들어 사용될 Spinner가 임의로 생성한 TextView 레이아웃을 참조하게 만들면 손쉽게 글자 Size는 물론 Color/Align 등을 변경 시킬 수 있습니다.

 
<!-- spinner_item.xml -->
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/tv_spitem"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:textSize="12pt"         
         android:textColor="#F00"
         android:gravity="center"
/>
/** Android-8 , 미리설정된 TextView 레이아웃을 참조 */
ArrayAdapter<?> a8Adapter = ArrayAdapter.createFromResource(
        this, R.array.spinner_arr_a8, R.layout.spinner_item);
a8Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
sp_a8.setAdapter(a8Adapter);

ArrayAdapter 설정에서 spinner_item.xml 을 연결 시켜 사용하면 됩니다.



Spinner의 배열이 고정되어 있으면 value/string.xml 에 string-array 를 이용하여 사용하면 되지만 배열의 값이 유동적으로 변해야 한다면 string-array를 사용하기엔 무리가 있더라구요.(string-array의 값을 유동적으로 바꾸는 방법은 찾아보지 않았습니다.)

java에서 string[] 배열을 만들어 spinner에 연결시키는 방법과 Custom ArrayAdapter를 만들어 TextView 설정도 할 수 있게끔 만들어 보았습니다.

/** Android-13 , Custom Adapter 참조 , 임의의 String[] 배열 사용*/
String[] a13s = {"Android-13","레이아웃#1","레이아웃#2"};
SpinnerAdapter a13Adapter = new SpinnerAdapter(this,
        android.R.layout.simple_spinner_item, a13s);
sp_a13.setAdapter(a13Adapter);
public class SpinnerAdapter extends ArrayAdapter<String> {
    Context context;
    String[] items = new String[] {};
 
    public SpinnerAdapter(final Context context,
            final int textViewResourceId, final String[] objects) {
        super(context, textViewResourceId, objects);
        this.items = objects;
        this.context = context;
    }
 
    /**
     * 스피너 클릭시 보여지는 View의 정의
     */
    @Override
    public View getDropDownView(int position, View convertView,
            ViewGroup parent) {
 
        if (convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(context);
            convertView = inflater.inflate(
                    android.R.layout.simple_spinner_dropdown_item, parent, false);
        }
 
        TextView tv = (TextView) convertView
                .findViewById(android.R.id.text1);
        tv.setText(items[position]);
        tv.setTextColor(Color.RED);
        tv.setTextSize(25);
        return convertView;
    }
 
    /**
     * 기본 스피너 View 정의
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(context);
            convertView = inflater.inflate(
                    android.R.layout.simple_spinner_item, parent, false);
        }
 
        TextView tv = (TextView) convertView
                .findViewById(android.R.id.text1);
        tv.setText(items[position]);
        tv.setTextColor(Color.BLUE);
        tv.setTextSize(12);
        return convertView;
    }
}

Custom ArrayAdapter를 이용해 spinner에 보여지는 font 설정과 spinner 클릭 시 보여지게 되는 view들의 속성까지 설정이 가능 합니다.

- Android-8은 spinner_item.xml 을 지정한 레이아웃
- Android-13은 임의의 배열과 Custom ArrayAdapter를
이용한 레이아웃입니다.
- Android-13 스피너 클릭 시 보여지게 되는 레이아웃.
(Custom ArrayAdapter의 getDropDownView에서 TextView의 속성을 변경하여 사용함.)



'Android' 카테고리의 다른 글

#Android EditText에서 SoftKeyboard 처리  (0) 2012.02.16
#Android ViewPager  (2) 2012.02.07
#Android Device별 기본 UI (Spinner)  (0) 2012.02.03
#Android 이미지 다운로드  (0) 2012.01.19
#Android 파일 다운로드  (0) 2012.01.18
Posted by ™설야
Android2012. 2. 3. 17:25

보통 레이아웃을 작성할 때 디바이스에 따른 Density 값 때문에 최대한 비율에 맞춰서 어느 디바이스에서든지 레이아웃의 틀어짐 없이 보여주려고 하는데 Android 기본 UI를 사용함에 있어서 디바이스 별로 차지하는 비율이 틀려질 때가 있어서 전체적인 레이아웃이 어색해지는 경우가 생긴 적이 있어서 글을 작성해 봅니다.

우선 많이 사용하는 Spinner를 가지고 있는 디바이스 별로 테스트 해보았습니다.


갤럭시S2

모토로이

갤럭시탭7

Device Spinner가 폰 별로 모양도 틀리고 심지어 모토로이의 경우엔 보여지는 Height의 비율이 상대적으로 좁기까지 하네요. 반면에 Android-8,-13의 경우엔 폰 별로 모양과 Height의 비율이 일정하고요.

요렇게 폰 별로 틀려지는 것을 어떻게 쉽게 통일 시킬 수 있을까 생각하다가 Android SDK 폴더에 있는 버전 별 플랫폼 폴더가 생각나서 들어가보니 9패치 이미지와 xml까지 다 있더군요.

안드로이드SDK폴더/platforms/platforms-13/data/res/

- xml은 drawable 폴더에
- 9패치 이미지들은 drawable-hdpi 폴더에 있습니다.

우선 Spinner와 관련된 이미지와 xml을 찾아 개발중인 프로젝트에다 복사만 해주시고 아래와 같이 사용될 Spinner에 Background로 지정해 사용할 수 있습니다.

<!—사용될 Spinner에 가져온 기본 컴퍼넌트 UI 사용 –->

<Spinner
    android:id="@+id/sp_a13"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/btn_dropdown_a13"
/>

Spinner말고도 다른 SDK내부에 있는 기본 UI들을 활용해 폰 별로 어색해지는 디자인을 살짝 보완할 수 있지 않을까 생각해봅니다.

 

Posted by ™설야
Android2012. 1. 19. 17:19


 어제 게시했던 소스를 확장하여 웹에서 이미지파일을 다운로드하여 화면에 뿌려주기까지 해보았습니다. 
여기에 추가된 부분은 다운로드 혹은 파일을 처리 중일땐 ProgressBar를 이용해서 사용자에게 알려주고 처리가 다 끝나면 서서히 화면에 나타나게끔 애니메이션을 넣었습니다.
 파일을 읽어 올때 지정된 캐쉬폴더에 파일이 있으면 우선 사용하게끔 하였고 없다면 다운로드 받게끔 처리했습니다.
 하단에 [모든 이미지 삭제] 버튼을 추가해서 다운로드 된 파일들을 삭제가 가능하게끔 구현하였구요!
주요 메소드와 프로젝트 파일을 올립니다. 소스에 나와있는 웹url은 구글 사이트도구를 사용하였고 간혹가다 다운로드가 안될 수 도 있으니 테스트하실때 안되면 다른 웹url에 있는 이미지파일을 지정해서 불러오시면 될것같네요. 

 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
    /**
     * 이미지뷰에 사용될 Bitmap 설정
     * @param fileName 가져와야 하는 파일명 
     */
	public void setImageBitmap(final String fileName) {
		mBitmap = null;
		mSpinner.setVisibility(View.VISIBLE);
		mImage.setVisibility(View.INVISIBLE);
		new Thread(){
			public void run() {
				try {
					//우선 장치에 저장되어 있는 파일을 읽어오려고 시도
					mBitmap = getBitmapResource(CACHE_FOLDER+fileName);
					if(mBitmap == null){//비트맵이 null이면 장치에서 읽어온 값이 없음.
						//다운로드 시작
						mBitmap = getBitmapResource(getDownloadFromUrl(fileName));
					}//null이 아니면 장치의 값을 읽어옴
					
					downloadHandler.sendEmptyMessage(DOWNLOAD_SUCCESS);
				} catch (Exception e) {
					Log.e("Download Failure","msg : "+e);
					downloadHandler.sendEmptyMessage(DOWNLOAD_FAILURE);
				}
			};
		}.start();
	}
	
	/**
	 * 핸들러
	 */
	Handler downloadHandler = new Handler(new Callback() {
		@Override
		public boolean handleMessage(Message msg) {
			switch (msg.what) {
			case DOWNLOAD_SUCCESS:
				mImage.setImageBitmap(mBitmap);
				mImage.setVisibility(View.VISIBLE);
				mSpinner.setVisibility(View.INVISIBLE);
				
				//다운받은 이미지가 서서히 나타나는 anim
				Animation anim = AnimationUtils.loadAnimation(mContext, R.anim.anim_type_image_alpha);
		    	mImage.startAnimation(anim);
				break;
			case DOWNLOAD_FAILURE:
				Toast.makeText(mContext, "이미지 다운로드 실패!", Toast.LENGTH_SHORT).show();
				mSpinner.setVisibility(View.INVISIBLE);
				mImage.setVisibility(View.INVISIBLE);
				break;
			}
			return true;
		}		
	});

어제 게시했던 메소드에 추가된 메소드중 주요 메소드는 위와 같습니다.
Thread를 이용해 처음엔 캐쉬폴더에서 파일을 불러오기 시도한 다음 그 값이 null이면 다운로드 받기 시작하고 결과를 Handler로 전달해주며 Handler에서 다운로드 성공/실패일때 구분하여 처리해 주었구요.
레이아웃 xml에선 ImageView와 ProgressBar의 크기와 위치를 동일하게 하여 visible과 invisible을 이용하였습니다.
 
 anim/anim_type_image_alpha.xml
1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:android="http://schemas.android.com/apk/res/android">
 
    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0"
        android:duration="1000" />
</set>

추가된 애니메이션 파일입니다.
마켓에서 리스트뷰형태로 항목이 나오면서 이미지들을 뿌려줄때 효과를 보니 이런 효과더라구요!
다른 애니메이션 효과를 줘도 멋질것같네요 ㅎㅎ

프로젝트 파일 첨부합니다.

 
Posted by ™설야
Android2012. 1. 18. 19:38

 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
	public String getDownloadFromUrl(String fileName){
		try{		
			File file = new File(CACHE_FOLDER);
		
			if(!file.isDirectory()){//캐시 디렉토리가 없으면 만들기 
				file.mkdir();
			}
			
			URL url = new URL(TEST_DOWNLOAD_URL+fileName);
			InputStream input = null;
			int count = 0;						
			
			input = new BufferedInputStream(url.openStream(), 8192);
			OutputStream output = new FileOutputStream(CACHE_FOLDER+fileName);
			byte data[] = new byte[1024];
			while ((count = input.read(data)) != -1) {
			    output.write(data, 0, count);
			}
			
			output.flush();
			output.close();
			input.close();	
			return CACHE_FOLDER+fileName;//패스 리턴 
		}catch(Exception e){//파일이 없다
			Log.e("downloadImage"," error : " +e);        	
			return null;
		}
		//return Drawable.createFromStream(((java.io.InputStream)new java.net.URL(url).getContent()), "name"); //Drawable 객체로 바로 가져오기
	}
	
	
    public Bitmap getBitmapResource(String path){
        return BitmapFactory.decodeFile(path, null);//bitmap 만들기
    }

  CACHE_FOLDER 에 지정된 url의 파일을 다운로드하여 Bitmap 객체로 만들어주는 샘플 소스입니다. 
다운로드 받은 파일을 활용해야할 경우가 많다면 구지 매번 다운로드받지 않고 임의의 폴더를 생성하여
그곳에 저장시킨 후 다음 번 어플 실행시 해당 폴더의 파일이름을 체크하여 있으면 사용할 수 있게끔 해주면 될것 같네요. 

사용법) 
1
mBitmap = getBitmapResource(getDownloadFromUrl(fileName));


 아예 Drawable 객체로 다운로드 받아와 리턴할수도 있더군요.
 

1
return Drawable.createFromStream(((java.io.InputStream)new java.net.URL(url).getContent()), "name"); //Drawable 객체로 바로 가져오기



Posted by ™설야
Android2010. 12. 7. 18:12

 오늘 Android SDK 2.3 업데이트 소식에 바로 SDK 업데이트와 이클립스 ADT 업데이트도 있길래 모두 업데이트 시켰습니다. 하지만 2.2 SDK에서 되던 나인패치가 실행이 안되더군요.

나인패치 실행 시 뜨던 오류 메세지

2.3 SDK 업데이트를 잘못했나 싶어 다시 받아도 봤지만 안되더군요. 이것저것 해보다가 안되서 2.2SDK 폴더와 2.3SDK 폴더를 비교해보니 tools/lib 폴더 안에 swing-worker-1.1.jar 가 2.3 SDK에는 존재 하지 않더라구요.
 2.2 SDK에 있던 swing-worker-1.1.jar 를 복사해다가 2.3 SDK (tools/lib 폴더)에 넣어주니 문제없이 나인패치가 실행이 되더라구요.
 왜 업데이트 되면서 저 파일이 누락되어버렸을까요?;;; 오전에 나인패치 사용할 일이 있었는데 보류하다가 이시간이 되서야 해결했네요 ㅜㅠ;;


Posted by ™설야
Android2010. 7. 15. 11:28

안드로이드 블로그 링크

우편번호 어플 ZipCode(Kr) 에 사용된 음성인식 방법

 

//음성 버튼을 클릭했을 때 불러오는 메소드

private void startVoiceRecognitionActivity() {

try{

     Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);

      

     intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);

     intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "찾고자 하는 /건물명을 말하세요.");

      

     startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);

}catch(Exception e){

            Toast.makeText(context,"음성 인식 어플리케이션이 없거나\n기능을 사용할 없습니다.",Toast.LENGTH_SHORT).show();

}

}

 

//음성인식 후 결과를 가져올 오버라이드 메소드

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

if (requestCode == VOICE_RECOGNITION_REQUEST_CODE && resultCode == RESULT_OK) {

ArrayList<String> matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);

String result = matches.toString();//결과값을 가져온다.

result = result.substring(1, result.length()-1); //결과값 앞뒤에 [ ] 붙는거 제거

et_dongname.setText(result); //결과값을 출력한다.

 

}

 

super.onActivityResult(requestCode, resultCode, data);

}

Posted by ™설야
Android2010. 4. 10. 02:41

 


 배운것들 이것저것 짜집기 해서 만든 첫번째 안드로이드 어플인 "우편번호 검색기" 입니다. 편지를 보낼일이 많아서 우체국에 자주가는데 갈때마다 모토로이로 3G를 이용, 인터넷을 통해 우편번호를 검색하거나 우체국에 있는 우편번호 책자로 하나하나 찾아가며 적는게 너무 불편해서 편의를 위해 만들게된 어플입니다.
 이제 막 배우면서 만들어본 어플이라 부족한면이 보이실겁니다. ^^ 버그나 개선사항이 생기면 서슴치 마시고 댓글남겨주시기 바래요~^^

p.s
 아직 마켓에서 검색이 되질 않길래 처음에 이름을 "우편번호 검색"에서 "우편번호" 로 바꾸고 "우편번호"로 검색을 하니 검색은 되네요 ㅜㅠ;;; 좀더 지켜봐야 할듯,,,

어플이름 : 우편번호 (ZipCode(kr))
어플용량 : 39.1KB
어플가격 : 무료(Free)
사용방법 :
 처음 실행시 혹은 우편번호 DB파일이 이상이 있는경우 DB파일을 SD카드로 다운로드 받게 됩니다.
다운로드 받은 DB파일과 사용하시면서 등록한 즐겨찾기 목록은 /sdcard/ZipCodeDB 폴더와 파일들을 생성합니다. 차후에 어플이 필요 없게 되시면 해당 폴더를 삭제해 주시면 됩니다.
 에뮬레이터에서 실행했을때는 처음에 전지역 DB만 가지고 검색을 하니 검색속도가 느리더군요. 그래서 스펙이 약한 기기에서도 DB검색 속도 향상을 위해서 전지역/도,광역시 를 구분해 넣었습니다. 전지역 보다는 각각의 도,광역시별 검색이 더 빠른 결과 목록을 가져옵니다.
 
 
 



다운로드 받으시려면 위의 QR코드를 이용하시거나 마켓에서 "우편번호"로 검색하세여~ 

Posted by ™설야
Android2010. 3. 17. 15:45

 각종 TableLayout 과 관련된 소스를 코딩 완료 후 에뮬레이터를 실행하면 레이아웃 자체가 보이지 않는 문제가 발생하더군요. 이것저것 알아본결과... 코딩하면서 자동으로 생성되는 import 구문이 문제였던 겁니다.


//코딩하다 발생하는 자동으로 잡아주는 잘못된 import 구문 
//import android.view.ViewGroup.LayoutParams; 

//이걸 적어주니 문제없이 레이아웃이 출력됩니다.
import android.widget.TableRow.LayoutParams;  


아마도 잘못된 LayoutParams 를 참조해서 발생한 문제 같네요.


해결방법을 알려준 사이트



Posted by ™설야