지난 월요일 화요일 이틀동안 POC (Proof of Concept)용으로 안드로이드 Native App 을 하나 개발 했습니다.
Native App 은 거의 2년만에 개발하는 것 같은데..
이번에 새로운 개념들도 여러개 배웠습니다.
그 내용들을 정리해 볼까 하는데요.
오늘은 그 중에 ViewFlipper 에 대해 정리해 보겠습니다.
공부하는 방법은 제가 Do It 안드로이드 앱 프로그래밍이라는 책에서 제공하는 동영상을 보고 개념도 다시 잡고 거기서 제공하는 소스를 다운받아서 보기도 하고 했는데요.
그 책에서 제공하는 viewFlipper 관련 예제 소스를 자세히 분석하면서 공부를 하겠습니다.
예제소스는 http://android-town.org/ 로 가면 무료로 제공하고 있으니 필요하신 분들은 받으셔서 보셔도 됩니다.
동영상강좌는 http://www.youtube.com/user/easyspub 에서 제공되고 있습니다.
책을 직접 구입하셔서 보시면 훨씬 더 도움이 될 것 같네요.
그럼 그 책에서 제공하고 있는 SampleViewFlipper 를 보겠습니다.
우선 첫번째 실행되는 layout xml을 보겠습니다.
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<org.androidtown.ui.flipper.ScreenViewFlipper
android:id="@+id/screen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp" />
</RelativeLayout>
Launcher Activity 의 Layout xml 은 위와 같이 돼 있습니다.
이 RelitiveLayout 의 대상 공간은 화면 전체이구요.
RelativeLayout 으로 세팅하고 그 내부에는 ScreenViewFlipper 클래스를 import 하는 태그만 있습니다.
이 flipper의 id 는 screen 이고 margin 10dp 로 한채로 대상 공간이 그 parent 인 RelativeLayout 을 꽉 채웁니다.
이클립스에 있는 Graphical Layout 을 통해 보면 아래와 같은 화면이 나옵니다.
이제 JAVA 소스코드를 봐야겠네요.
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
바로 이 MainActivity 가 첫번째 화면인데요. onCreate() 메소드내에 위에서 본 activity_main.xml 을 Content View로 세팅을 했습니다.
그게 다 입니다.
밑에 있는 onCreateOptionMenu() 메소드는 override 한 것인데 안드로이드 디바이스 밑의 menu 버튼을 누르면 나오는 메뉴들을 세팅하는 메소드 입니다.
실제 이 앱과는 관련이 없으니까 무시하셔도 됩니다.
결국은 앱을 실행하는 첫번째 Activity에는 아무론 것도 화면에 표시를 하지 않네요.
이제 activity_main.xml에서 import한 ScreenViewFlipper.java 를 봐야겠습니다.
그럼 우선 이 ScreenViewFlipper에서 사용하는 layout 파일인 screenview.xml을 보겠습니다.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:id="@+id/buttonLayout"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
>
</LinearLayout>
<ViewFlipper
android:id="@+id/flipper"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</ViewFlipper>
</LinearLayout>
일단 LinearLayout 을 사용했습니다. width와 height가 match_parant니까 위의 xml 파일에서 세팅된 <org.androidtown.ui.flipper.ScreenViewFlipper ...... />의 크기 만큼 그 대상 공간이 됩니다.
여기서는 계속 화면 전체가 되겠죠.
그 다음 LinearLayout 내부에 또 LinearLayout이 있습니다. 그 크기는 wrap_content 로 돼 있는데 그것은 이 LinearLayout에 들어가는 내용의 크기 만큼 설정을 하겠다고 세팅돼 있습니다.
그런데 그 안에 아무것도 없네요. 즉 화면에 표시할 게 아무것도 없습니다. 나중에 혹시 java 파일에서 이 LinearLayout을 불러내서 다른 object를 setting 하면 그 때 화면에 뭔가가 표시 될 수는 있을 겁니다.
(id가 buttonLayout 이니까 이 id로 불러낼겁니다.)
그 아래는 <ViewFlipper> 태그가 있습니다. 여기에 오늘 공부하는 ViewFlipper를 표시할 겁니다.
여기까지 보니까 위에는 버튼이 달릴거고 (내부 LinearLayout id 가 buttonLayout인것을 가지고 아직까지는 그냥 추정해 보는 겁니다.) 그 아래에 ViewFlipper 가 달려서 페이지 전환이 이뤄질 것 같습니다.
아직까지는 이 Layout에 어떤 VIew나 Widget이 표시되지는 않습니다.
ViewFlipper에 대한 Android Developer 싸이트의 설명은 이렇습니다.
두개 이상의 View들이 add돼 있고 이 view들이 animate 될 간단한 ViewAnimator. 한번에 한 child만 보인다. 설정을 한다면 일정한 interval을 두고 각각의 child 를 자동으로 flip 되도록 할 수 있다.
flip이라는 의미가 뒤집다라는 거니까 페이지들을 child로 설정했다면 이 페이지가 뒤집히는 효과를 주면서 화면이 전환되게 할 수 있겠네요.
또 view에는 여러개가 해당 될 수 있으니까 다른 object 별로도 이런 flip 효과를 줄 수 있겠습니다.
그럼 이제 본격적인 내용이 있는 ScreenViewFlipper를 한번 분석해 보죠.
public class ScreenViewFlipper extends LinearLayout implements OnTouchListener {
/**
* Count of index buttons. Default is 3
*/
public static int countIndexes = 3;
/**
* Button Layout
*/
LinearLayout buttonLayout;
/**
* Index button images
*/
ImageView[] indexButtons;
/**
* Views for the Flipper
*/
View[] views;
/**
* Flipper instance
*/
ViewFlipper flipper;
/**
* X coordinate for touch down
*/
float downX;
/**
* X coordinate for touch up
*/
float upX;
/**
* Current index
*/
int currentIndex = 0;
public ScreenViewFlipper(Context context) {
super(context);
init(context);
}
public ScreenViewFlipper(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
/**
* Initialize
*
* @param context
*/
public void init(Context context) {
setBackgroundColor(0xffbfbfbf);
// Layout inflation
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.screenview, this, true);
buttonLayout = (LinearLayout) findViewById(R.id.buttonLayout);
flipper = (ViewFlipper) findViewById(R.id.flipper);
flipper.setOnTouchListener(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
params.leftMargin = 50;
indexButtons = new ImageView[countIndexes];
views = new TextView[countIndexes];
for(int i = 0; i < countIndexes; i++) {
indexButtons[i] = new ImageView(context);
if (i == currentIndex) {
indexButtons[i].setImageResource(R.drawable.green);
} else {
indexButtons[i].setImageResource(R.drawable.white);
}
indexButtons[i].setPadding(10, 10, 10, 10);
buttonLayout.addView(indexButtons[i], params);
TextView curView = new TextView(context);
curView.setText("View #" + i);
curView.setTextColor(Color.RED);
curView.setTextSize(32);
views[i] = curView;
flipper.addView(views[i]);
}
}
/**
* Update the display of index buttons
*/
private void updateIndexes() {
for(int i = 0; i < countIndexes; i++) {
if (i == currentIndex) {
indexButtons[i].setImageResource(R.drawable.green);
} else {
indexButtons[i].setImageResource(R.drawable.white);
}
}
}
/**
* onTouch event handling
*/
public boolean onTouch(View v, MotionEvent event) {
if(v != flipper) return false;
if(event.getAction() == MotionEvent.ACTION_DOWN) {
downX = event.getX();
}
else if(event.getAction() == MotionEvent.ACTION_UP){
upX = event.getX();
if( upX < downX ) { // in case of right direction
flipper.setInAnimation(AnimationUtils.loadAnimation(getContext(),
R.anim.wallpaper_open_enter));
flipper.setOutAnimation(AnimationUtils.loadAnimation(getContext(),
R.anim.wallpaper_open_exit));
if (currentIndex < (countIndexes-1)) {
flipper.showNext();
// update index buttons
currentIndex++;
updateIndexes();
}
} else if (upX > downX){ // in case of left direction
flipper.setInAnimation(AnimationUtils.loadAnimation(getContext(),
R.anim.push_right_in));
flipper.setOutAnimation(AnimationUtils.loadAnimation(getContext(),
R.anim.push_right_out));
if (currentIndex > 0) {
flipper.showPrevious();
// update index buttons
currentIndex--;
updateIndexes();
}
}
}
return true;
}
}
우선 메소드들을 선언하기 전에 나오는 object들을 선언하는 것부터 보겠습니다.
첫번째는 countIndexes=3; 인데 주석을 보니까 index 버튼들의 숫자라고 하네요. 디폴트는 3이구요.
그 다음 LinearLayout을 buttonLayout 이라는 이름으로 하나의 객체를 만들어 놨습니다.
아직 정확하게는 모르지만 이 객체에 screenview.xml 에 있었던 buttonLayout 이라는 id를 가진 LinearLayout 을 세팅할 것 같네요.
그리고 indexButtons 라는 이름으로 ImageView 배열을 선언했구요. 여기에는 위에서 3개로 선언된 index button 이미지가 세팅될것 같습니다.
그 다음에는 views라는 이름으로 View 배열이 있습니다. 주석에는 Flipper들을 위한 View들이라고 돼 있네요.
다음줄에서 ViewFlipper의 instance를 만들었습니다. 그 이름은 flipper 이구요.
그 다음은 down시 x 좌표를 받을 downX라는 이름으로 float 객체를 만들었고 up시 x 좌표를 받을 upX도 있습니다.
그리고 현재의 index는 0이라고 선언한 줄이 나옵니다. 이름은 currentIndex 이고 정수형입니다.
메소드에 대한 분석들은 다음 글에서 이어나가겠습니다.
'WEB_APP > Android' 카테고리의 다른 글
[CookBook] 원격에서JSON 데이터 받아와서 사용하기 (0) | 2013.09.20 |
---|---|
[CookBook] Tweening Animation 소스 분석하기 -2- (0) | 2013.09.19 |
[CookBook] Tweening Animation 소스 분석하기 -1- (0) | 2013.09.18 |
[PageSliding] SamplePageSliding 소스 파일 분석하기 (0) | 2013.09.17 |
[ViewPager] SampleVIewPager 소스 파일 분석하기 -2- (0) | 2013.09.16 |
[ViewPager] SampleVIewPager 소스 파일 분석하기 -1- (0) | 2013.09.15 |
[ViewFlipper] SampleVIewFlipper 소스 파일 분석하기 -3- (0) | 2013.09.14 |
[ViewFlipper] SampleVIewFlipper 소스 파일 분석하기 -2- (0) | 2013.09.13 |
안드로이드 프로그래밍 관련 메모... (0) | 2013.09.09 |
안드로이드 개발 환경 구축하기 (1) | 2013.09.06 |