Le_Penseur
[안드로이드 스튜디오] Ch10. 버튼 이펙트 & 핵심 수신기(ButtonEffect & KeyListener) 본문
[안드로이드 스튜디오] Ch10. 버튼 이펙트 & 핵심 수신기(ButtonEffect & KeyListener)
LePenseur 2019. 8. 28. 11:102019년 8월 28일 (수)
창업의 길로 가기 위한 두번째 걸음, [안드로이드 스튜디오]로 향해보자!
*질적으로 많이 부족한 글입니다. 지적 및 조언 환영합니다.
*이 글에선 "안드로이드 스튜디오"를 줄여서 "안스" 라고 표현합니다. 참고 바랍니다.
우선, 본인은 학원에서 'JAVA' 기초 수업을 선수강했다. 안드로이드 스튜디오를 배우기 위해선 피할 수 없는 언어이기 때문이다.
(물론 Kotlin 도 있지만, 대한민국에선 아직 JAVA의 파워가 어마어마 하다고..)
이번글에서는 [버튼 클릭전] - [버튼 클릭후] 의 모습을 다르게 하는 방법에 대해 알아보고,
<차례>
1. MyButtonEffect
2. MyKeyListener
1. MyButtonEffect
1.1 결과
설명: 버튼 클릭시 그림 또는 컬러가 바뀌어야 한다.
클릭시 Button1은 놀라는 사람, Button2는 좀더 진한 종, Button3은 배경색이 분홍색, Button4는 안스 제공 기본 이펙트 를 보여준다.
이번 프로젝트를 위해선 총 4개의 xml파일, 1개의 java파일이 필요하다.
으악! 벌써 복잡한 스멜이 느껴진다. 하지만 걱정마시라, 각각의 파일보다 전체적인 프로젝트에 집중하면 크게 부담스럽지 않다.
"(어플제작에서 길을 잃지 않으려면) 나무보다는 숲을 보자." - Le Penseur (199* ~)
1.2 코드
1.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">
<!--
버튼 클릭 효과 주기!
- 이제는 onClickListener뿐만 아니라, xml파일을 이용하여 효과를 주는 방법을 알아본다.
- 상태값에 따라 다른 효과를 주기 위해서는 selector를 이용하여 정의하여야 한다.
- selector 만들때는 drawable파일에서 만든다.
-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button1"
android:textSize="40dp"
android:textColor="#ffffff"
android:background="@drawable/button_selector"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button2"
android:textSize="40dp"
android:gravity="center"
android:background="@drawable/image_select"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button3"
android:textSize="40dp"
android:gravity="center"
android:background="@drawable/selector_view"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button4"
android:textSize="40dp"
android:gravity="center"
android:background="?attr/selectableItemBackground"
/>
<!--
따로 색깔,그림 을 지정해주거나 그런게 아닌이상 이 걸 쓰면 된다. 아주 효욜적이다.
android:background="?attr/selectableItemBackground"
: 특정 뷰 안에 제한되어 터치시 퍼져나가는 효과
android:background="?attr/selectableItemBackgroundBorderless"
: 제한 구역 없이 터치시 퍼져나가는 효과
API21이상에서는
클릭효과를 주고싶은 vIEW의 Background 밑에 속성을 지정하면 클릭효과가 생긴다.
-->
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
설명: 따로 id를 생성해줄 필요없다. 이 프로젝트에서는 기능을 추가할것이 아니기때문이다.
1.2.2 button_shape2.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<solid
android:color="#fd4381"
/>
</shape>
설명: 3번째 버튼의 효과다. res.drawable 폴더에 새로운 파일을 만들어주면 되는데, 디폴트값이 shape이 아닌 selector일것이다. 그걸 바꿔주고 위 코드를 작성하면 된다.
android: shape 에서는 [사각형, 타원형, 원형, 선] 이렇게 총 4종류가 있다.
1.2.3 selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true"
android:drawable="@drawable/button_shape2"
/>
<item
android:state_focused="true"
android:drawable="@drawable/button_shape2"
/>
<item
android:drawable="@drawable/button_shape1"
/>
</selector>
설명: 위 코드와 동일한 방법으로 새로운 파일을 만든것이다. 다만, 이번에는 디폴트값을 그대로 사용하고 그안에서 item을 추가할것이다. 그래서 selector는 뭐하는 놈인가? 한마디로 정리하자면, "상태에 따라 다른 이미지를 보여주는 리소스" 정도 되시겠다.
그래서 로직을 잘 보면, state pressed, focused 등 눌렀을때, 집중되었을때와 같은 오더가 내려지고 그 밑에 어떤 이미지가 나오게 할지도 지정하는것을 볼 수 있다. 오더의 종류는 총 5가지 이고, 이 안에서 true/false 를 결정하면 된다.
1. android:state_pressed :"true" 현재 클릭이 된 경우./ "false" 클릭이 안된 경우
2. android:state_enabled : "true" 현재 사용이 가능한 경우 / "false" 현재 사용이 불가능한 경우
3. android:state_selected :"true" 현재 선택이 된 경우/ "false" 현재 선택이 안된 경우
4. android:state_focused : "true" 현재 포커스를 가진 경우/ "false" 현재 포커스를 안가진 경우
5. android:state_checked : "true" 현재 체크된 경우/ "false" 현재 체크가 안된 경우
1.2.4 image_select.xml
version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true"
android:drawable="@drawable/a_alarm"/>
<!--버튼 클릭전 -->
<item
android:state_pressed="false"
android:drawable="@drawable/b_alarm"
/>
</selector>
설명: 위와 동일하다.
1.2.2 MainActivity.java
package com.example.mybuttoneffect;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
설명: 이번엔 기능을 따로 추가하지않았다.
1. MyKeyListener
1.1 결과
설명: 이번 프로젝트의 목표는 오른쪽 위에 있는 세로의 [...] 메뉴 버튼을 제작 및 그안에 들어갈 리스트까지 지정하는 것이다.
그런데 메뉴라는 버튼을 독립적으로 만들어서 독립적으로 사용 할 순 없을까? 이에 대한 의문점을 해결할 것이다.
InputData 는 EditText란에 숫자또는 글자를 입력했을때 그에 합당하는 숫자를 보여주는데..
이 작업이 정확히 무슨의미가 있나 싶긴하다. (...)
결론은 어플 상단 오른쪽위에 메뉴버튼을 생성하고 그안에 들어갈 메뉴 리스트 작성까지가 이 어플의 최종목표다.
1.2 코드
1.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">
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25dp"
android:hint="input"/>
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25dp"
android:text="InputData : "
/>
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="menu"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
설명: 이번 디자인란에도 특별한것은 없다. 그저 현 프로젝트는 기능이 '주'이기에, id생성을 꼭 해주자.
1.2.2 main_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!--
menu파일의 정식 명칭 main_menu.xml (다른이름으도 상관없지만, 보통 "main_"으로 시작해야함)
-->
<item android:id="@+id/add"
android:title="@string/Add"/>
<item android:id="@+id/edit"
android:title="@string/Edit"/>
<item android:id="@+id/email"
android:title="@string/Email"/>
</menu>
설명: 여태까진 res폴더에 있는 drawable폴더를 주로 사용했는데, 이번에는 menu라는 폴더에서 작업을 한다.
new resource file을 만들어주자. 단, 이름은 main_### 으로 시작하도록 하자.
기존의 리스트뷰와 동일하게, 아이템을 추가시킨다. 다른점이라면 "android:title=@string/##" 라는 아이디 기반 로직을 이용한다는것이다.
그 이유는 기존의 리스트뷰는 아이템을 '선택'만 하는것이었다면, 메뉴의 리스트는 아이템에 '기능'을 추가해야하기 때문이라고 생각한다.
Add, Edit, Email이라는 메뉴 리스트를 총 3개 추가했다.
1.2.3 strings.xml
<resources>
<string name="app_name">MyKeyListener</string>
<string name="Add">Add</string>
<string name="Edit">Edit</string>
<string name="Email">Email</string>
</resources>
설명: 또다른 xml파일이 필요하다. 그런데 이 xml파일은 새롭게 생성한건 아니고, 기존에 존재하던 파일이다.
1.2.2 MainActivity.java
package com.example.mykeylistener;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private EditText editText;
private Button button;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//객체 설정
editText = (EditText) findViewById(R.id.editText);
textView = (TextView) findViewById(R.id.textView);
button = (Button) findViewById(R.id.button);
// OnKeyListener
// - OnKey메소드를 재정의 하여야 한다. (왜?
editText.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int i, KeyEvent keyEvent) {
// - int i: keyCode (키값, 아스키코드와 유니코드랑은 다르다.)
// - KeyEvent: KeyEvent는 모션 이벤트와 사용방법이 거의 비슷하다.
//if(keyEvent.getAction() == KeyEvent.ACTION_UP){
//이 if문은 있어도되고 없어도 된다.
//keyEvent.ACTION_DOWN
//예전 코드들을 살펴 보면, DOWN으로 처리하였다.
//OREO 버전에서는 다운으로 처리하면 제대로 되질 않는다.
//키가 눌러졌을때 0~9까지의 숫자키 거르기.
textView.setText("InputData : " + i);
if (i >= KeyEvent.KEYCODE_0 && i <= KeyEvent.KEYCODE_9) {
Toast.makeText(
getApplicationContext(), "number" + i, Toast.LENGTH_LONG).show();
}
return false;
// true를 반환하면... event 객체가 내부적으로 항상 이벤트를 발생하고있다고 생각하게 된다.
// 우린 event를 필요시에만 호출해야하기 때문에, 필요한 경우에만 해당 이벤트를 처리한후에 false를 반환 함으로써
// 항상 event를 발생하고 있다는 생각을 하지 않도록 해야 한다.
// 걍 왠만하면 false로 두라.
}
});
}
// 메뉴 바를 활성화 시키기 위해서는 OnCreateOptionsMenu랑 onOptionsItemSelected 를 @override(재정의) 해야한다.
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
//하나의 메뉴 아이템이 선택되었을때, 현재 메소드 실행!
switch (item.getItemId()){
case R.id.add:
textView.setText("Selected ADD");
break;
case R.id.edit:
textView.setText("Selected EDIT");
break;
case R.id.email:
textView.setText("Selected EMAIL");
break;
}
return super.onOptionsItemSelected(item);
}
}
'개인(Personal) > 안드로이드 (Andorid Studio)' 카테고리의 다른 글
[안드로이드 스튜디오] Ch12. 다이얼로그 & 인텐트 (Dialog & Intent) (0) | 2019.08.30 |
---|---|
[안드로이드 스튜디오] Ch11. 다이얼로그(Dialog) (1) | 2019.08.29 |
[안드로이드 스튜디오] Ch9. 버튼 클릭 이벤트 처리 & 인플레이터(OnClickListener & Inflater) (0) | 2019.08.27 |
[안드로이드 스튜디오] Ch8. 리스트뷰 이벤트처리 (ListView Event Handling (0) | 2019.08.25 |
[안드로이드 스튜디오] Ch7. 이벤트 처리(Event Handling) (0) | 2019.08.23 |