Le_Penseur

[안드로이드 스튜디오] Ch8. 리스트뷰 이벤트처리 (ListView Event Handling 본문

개인(Personal)/안드로이드 (Andorid Studio)

[안드로이드 스튜디오] Ch8. 리스트뷰 이벤트처리 (ListView Event Handling

LePenseur 2019. 8. 25. 15:55
반응형

2019년 8월 25일 (일)

 

창업의 길로 가기 위한 두번째 걸음, [안드로이드 스튜디오]로 향해보자!

 

*질적으로 많이 부족한 글입니다. 지적 및 조언 환영합니다.

*이 글에선 "안드로이드 스튜디오"를 줄여서 "안스" 라고 표현합니다. 참고 바랍니다.

 

 

우선, 본인은 학원에서 'JAVA' 기초 수업을 선수강했다. 안드로이드 스튜디오를 배우기 위해선 피할 수 없는 언어이기 때문이다.

(물론 Kotlin 도 있지만, 대한민국에선 아직 JAVA의 파워가 어마어마 하다고..)

 

이번글에서는 저번글에서 배운 이벤트처리를 조금 더 깊게 다가가는 시간을 갖으며, 리스트뷰에 대해서도 알아보고 간다.

 


<차례>

1. MyCatchEvent

2. ListViewEvent


 

1. MyCatchEvent

 

1.1 결과

사진1

 

설명: 결과물은 저번글과 비슷하게 Catch Event 버튼을 클릭하면 빨간색 박스안에 "event" 와 "no event' 가 번갈아 뜬다.

그러나 다른점은, 빨간 박스안에 "Event" 가 뜬 후에 터치(또는 클릭)을 하면서 움직이게 되면 내 손가락(또는 마우스)의 x,y 좌표가 'Result'란에 나오게 된다.

그에 반해  "No Event"상태에서 터치를 할 시에는 Toast형식으로 알림이 "action down!" 이라고 뜨며, 'Result'란에도 "DOWN"이 뜬다.

잘 풀리지 않을때, 밑의 코드를 통해 알아보자.

 

1.2 코드

 

1.2.1 activity_main
<?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">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/textView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Result : "
            android:textSize="30dp" />
        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Catch Event!!"
            android:textSize="30dp"
            android:layout_alignParentBottom="true" />
        <TextView
            android:id="@+id/textView2"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:background="#ff0000"
            android:textColor="#000000"
            android:textSize="30dp"
            />



    </RelativeLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

1.2.2 MainActivity
package com.example.mycatchevent;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    //멤버변수 작업
    private Button button;
    private TextView textView1,textView2;
    private boolean check;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //객체화 작업
        textView1 = (TextView)findViewById(R.id.textView1);
        textView2 = (TextView)findViewById(R.id.textView2);
        button = (Button) findViewById(R.id.button);

        //Log.i("check",check + "");

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(check){
                    textView2.setText("No Event");
                    // 위에서 논리형 변수 check를 만들었었고, 그걸 이용하는것이다.
                    // 논리형의 default값은 off다. 따라서 여기 OnClickListener에서 의미하는 바는
                    // "누르지 않았을때, 또는 반대(-)의 값을 띤다." 는 것이다.
                    // 그리고 그럴땐 "No Event"(text)라고 뜨도록 설정(set)했다.
                    // 어디에? 바로 빨간 네모박스(textView2)위에!
                }else{
                    textView2.setText("Event");
                    // 위와 정확히 반대다. 양(+, on)의 값을 띨때는 "Event"라고 뜨도록 설정했다.
                }

                check =! check;
                // 부정연산자를 이용: 참을 거짓으로, 거짓을 참으로 -> 이 원리를 다시 check에 저장.
                // 왜?
            }
        });

        //textView2를 터치할때 이벤트 처리를 할 것 이다.
        //그러면 우리는 여기서 OnTouchListener를 사용할 것 이다.

        textView2.setOnTouchListener(new View.OnTouchListener() {

            //MotionEvent에는 3가지의 상태값이 있다.
            //1.Action_DOWN: 손가락을 내린다.
            //2.Action_UP: 손가락을 땐다.
            //3.Action_MOVE: 손가락을 움직인다.
            //MotionEvent의 상태값은 getAction()메소드를 통해서 상태를 구별할 수 있다.
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {

                String msg = null; //TextView1에 출력될 문자열
                int x = 0; //x좌표
                int y = 0; //y좌표

                switch (motionEvent.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        Toast.makeText(MainActivity.this,"Action Down!!!", Toast.LENGTH_SHORT).show();
                        msg = "Result : DOWN";
                        break;

                    case MotionEvent.ACTION_UP:
                        x = (int) motionEvent.getX();//x축의 좌표를 반환시키는 메소드
                        y = (int) motionEvent.getY();//y축의 좌표를 반환시키는 메소드
                        msg = "Result : UP (x : " + x + " , y : " + y + ")";

                    case MotionEvent.ACTION_MOVE:
                        x = (int) motionEvent.getX();//x축의 좌표를 반환시키는 메소드
                        y = (int) motionEvent.getY();//y축의 좌표를 반환시키는 메소드
                        msg = "Result : UP (x : " + x + " , y : " + y + ")";


                        break;
                }

                textView1.setText(msg);




                return check;
                //반환값이 true이면 "여기서 이벤트 처리가 완료 되었다" 는 뜻.
                // 화면 적용을 요구하게 된다.
                // false 면 "이벤트 처리가 완료되지 않았다." 라는 걸 뜻한다.
            }
        });

    }
}

 

 

2. ListViewEvent

 

2.1 결과

 

사진2

 

설명: 결과물의 레이아웃은 간단하다. 위에는 제목, 밑에는 리스트가 들어갈 빈 공간과 함께 리스트를 더해줄 버튼을 추가해주면 된다.

단, 추가되는 리스트들은 이름이 겹치지 않고, 추가되는 순서별로 이름이 정해진다. 1부터 ~00까지.

또 좀더 특징이 있다면, 이번엔 결과물 출력을 위해선 xml파일과 java파일이 각각 한개씩 더 추가가 되어야 한다는 것 이다.

밑의 코드를 보고 이해해보자.

 

2.2 코드

 

2.2.1 activity_main.xml
<?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">

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

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="ListViewEvent"
            android:textSize="20dp"
            android:gravity="center" />

        <ListView
            android:id="@+id/myList"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:transcriptMode="alwaysScroll">
            <!-- alwaysScroll이 뭐야? 아이템 추가시 Bottom 아이템 위치로 '자동 스크롤'하는 모드
            (1) disabled: transcriptMode를 사용하지 않겠다. (디폴트값)
            (2) normal: 마지막 아이템이 화면에 표시된 상태에서 데이터 변경을 받은 경우 '자동 스크롤' 하는 모드
            (3) notifyDataSetChanged() (데이터 변경 메소드)가 실행된 경우
            (4) alwaysScroll: 아이템이 화면에 표시중인 여부와 상관 없이 무조건 스크롤
            -->


        </ListView>

        <Button
            android:id="@+id/addBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="add"
            />



    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

 

2.2.2 list_form.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:descendantFocusability="blocksDescendants">

    <!-- 리스트의 각 항목들을 구성할 xml파일 입니다. 
     android:descendantFocusability="blocksDescendants"
     : Focuability가 자식의 포커스를 해제하는 기능, 쉽게 생각해서 이쪽에 집중하는 것을 막겠다는 뜻
     더 쉽게 말해서, 어플을 처음켰을때 포커스가 제일 나중에 추가된 자식뷰로 가는걸 막는다는 것.
     예를 들어 내가 리스트를 100개를 만들었는데, 어플을 킬때마다 첫화면 마지막 리스트 차례인 100으로 포커스가
     맞춰지는걸 예방함.
     -->
    <TextView
        android:id="@+id/list_form_txt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20dp">





    </TextView>

</LinearLayout>

 

2.2.3 MyAdapter.java
package com.example.mylistviewevent;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import org.w3c.dom.Text;

import java.util.ArrayList;

public class MyAdapter extends ArrayAdapter<String>
        implements AdapterView.OnItemClickListener {

    private Context context;
    private ArrayList<String> list;
    private ListView myList;

    //생성자 (이번엔 받을게 좀 많을거다)

    public MyAdapter(Context context, int resource, ArrayList<String> list, ListView myList){
        super(context, resource, list);

        this.context = context;
        this.list = list;
        this.myList = myList;
    }

    //밑의 메소드는 실제 뷰를 만드는 메소드 이다.
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        // 인플레이션(xml 레이아웃에 정의된 내용이 메모리에 객체화가 되는 과정)을 해줘야한다.
        // 밑이 바로 인플레이션을 하기위한 준비작업이다.
        LayoutInflater layoutInflater =
                (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        //여기에서 이제 인플레이션이 시작(진행)되는 것 이다.
        convertView = layoutInflater.inflate(R.layout.list_form, null);

        TextView txt_form = (TextView)convertView.findViewById(R.id.list_form_txt);

        String str = list.get(position); // 문자열 값을 빼준다.

        txt_form.setText(str);

        //원래 같으면 newOnItemClickListener 인데 this를 넣는 이유는 이 클래스 자체가 onclickListener이기 때문이다. 하하!
        //그런데 왜 myList안에 '클릭시의 기능' 을 넣어줄까?
        //왜냐하면 우리는 텍스트가 아니라 리스트에 신경을 쓰기때문!
        myList.setOnItemClickListener(this);


        return convertView;
    }

    //내부클래스를 만드는것이 아니라 이번엔 기존의 것을 상속한다.
    //int i : 포지션을 뜻 한다.
    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
        Toast.makeText(context.getApplicationContext(),list.get(i),Toast.LENGTH_LONG).show();

    }
}

 

 

2.2.3 MainActivity.java
package com.example.mylistviewevent;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Adapter;
import android.widget.Button;
import android.widget.ListView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    // 멤버변수 생성 (나의 재료)
    private Button addBtn;
    private ListView myList;
    private ArrayList<String> list;
    private int cnt = 0;
    private MyAdapter adapter = null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 객체 생성 (자바는 객체지향 알지?)
        addBtn = (Button)findViewById(R.id.addBtn);
        myList = (ListView)findViewById(R.id.myList);
        list = new ArrayList<String>();
        adapter = new MyAdapter(MainActivity.this,R.layout.list_form,list,myList);
        //(MainActivity.this (즉, 가장 상위의 view), 아이템으로쓸 레이아웃, 이안에서 실행시킬 리스트, 이녀석이 실행될 뷰)


        // setAdapter: Adapter에 연결시키고, 방금 위에 객체화 시킨 adapter를 처리한다.
        //아! (괄호안) 은 즉, "처리할 데이터"를 말하는구나!
        myList.setAdapter(adapter);

        // 자, 이제 버튼을 누르면 어떤 기능이 나오는지 추가하고 마무리해보자.
        addBtn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {

                //버튼 클릭할때마다 카운트를 증가시키면서 list에 내용을 추가할 것 이다.
                cnt++;
                list.add("list " + cnt);

                if (myList != null) {
                    adapter.notifyDataSetChanged(); //이걸 써야 list값이 추가 될때 마다 listview를 갱신할수있다.
                }
            }

        });


    }


}

 

반응형
Comments