Inprevious post, I had talked about some popular designs of Floating Action Button (FAB) - a component of Design Support Library. Beside that, there is a design fromInbox application(developed by Google) which containing some FABs are combined into a group and they will be shown after the "representative button" clicked. This design called Floating Action Menu:
Up to now, there is no official component from Google which allows us making this design so we must use third-party library to building a Floating Action Menu (FAM). Fortunately, libraries to resolve this problem is not unpopular! In this post, I will use a third-party developed byDmytro Tarianyk Clans. It's very simple to implement and solving this problem quickly! DEMO VIDEO:
Import the library
Adding this dependency to your application levelbuild.gradle: dependencies { compile 'com.github.clans:fab:1.6.4'} Now, we have two objects calledFloatingActionMenuandFloatingActionButtonto build this layout.
Some important features
FloatingActionMenuhas some attributes in xml that we have to pay attention:
fab:menu_fab_label: Label for Menu button
fab_colorNormal,fab_colorPressed,fab_colorRipple: Change button color based on it's status.
fab_showAnimation,fab_hideAnimation: Animation when menu expand/collapse.
menu_labels_position: Position of buttons label (left/right).
//handling menu status (open or close) fam.setOnMenuToggleListener(new FloatingActionMenu.OnMenuToggleListener() { @Override public void onMenuToggle(boolean opened) { if (opened) { showToast("Menu is opened"); } else { showToast("Menu is closed"); } } });
//handling each floating action button clicked fabDelete.setOnClickListener(onButtonClick()); fabEdit.setOnClickListener(onButtonClick()); fabAdd.setOnClickListener(onButtonClick());
fam.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (fam.isOpened()) { fam.close(true); } } }); }
지오코딩(GeoCoding) 이란 '주소나 지명' 을 '좌표 (위도, 경도)' 로 변환시키는 작업이다. 혹은 반대로 '좌표(위도, 경도)' 를 '주소나 지명' 으로 변환하는 작업 (역 지오코딩: Reverse GeoCoding) 이라 한다.
예를 들면 '서울 시청' 을 지오코딩 하면 좌표가 ( 37.56647, 126.977963 ) 이 튀어 나오는 겁니다. 사실 이런 서비스는 이미 구글맵 등에서도 제공되었죠. 구글맵에서 특정 지점 위에서 마우스우클릭 - '이곳이 궁금한가요?' 실행하면 위도, 경도 가 나왔죠.
지오코딩 서비스는 역시 안드로이드 플랫폼을 만든 구글 답게 구글에서 제공해주는 거고, 안드로이드 API 에Geocoder객체 +Address객체 를 통해 서비스 사용이 가능합니다.
안드로이드에서 지오코딩을 구현하는 주요 Step 은 다음과 같습니다.
Step1 :메니페스트 파일에 인터넷(INTERNET) 과 위치정보 서비스(ACCESS_FINE_LOCATION) 권한을 받아옵니다
Step2 :Geocoder 객체 생성
Step3 :'좌표(위도, 경도)' 를 '주소나 지명' 으로 변환하는 경우 getFromLocation() 메소드 사용. 결과는 List<Address> 형태
: '주소나 지명' 을 '좌표(위도, 경도)' 으로 변환하는 경우
getFromLocationName() 메소드 사용. 결과는 List<Address> 형태
Step4 :Address 객체의 toString(), getCountryName(), getLatitude(), getLongitude(), getPostalCode(), getPhone() 메소드 등을 통해 세부정보 추출 가능
아래 에제에서는
1) '좌표(위도, 경도)' 를 '주소나 지명' 변환
2) '주소나 지명' 을 '좌표(위도, 경도)' 으로 변환
두가지를 해볼거고, 각각에 대해 변환된 문자열 출력과, 변환된 위도,경도 좌표를 통해 지도를 보여주는 것을 구현해봅니다. 이때 지도는 묵시적 인텐트 (implicit intent) 로 호출합니다. (묵시적 인텐트 에 대해서는 지난 포스팅 참조 → 클릭)
[AndroidManifest.xml]
인터넷(INTERNET) 과 위치정보 서비스(ACCESS_FINE_LOCATION) 권한을 받아옵니다
// 지오코딩(GeoCoding) : 주소,지명 => 위도,경도 좌표로 변환 // 위치정보를 얻기위한 권한을 획득, AndroidManifest.xml // ACCESS_FINE_LOCATION : 현재 나의 위치를 얻기 위해서 필요함 // INTERNET : 구글서버에 접근하기위해서 필요함 final TextView tv = (TextView) findViewById(R.id.textView4); // 결과창 Button b1 = (Button)findViewById(R.id.button1); Button b2 = (Button)findViewById(R.id.button2); Button b3 = (Button)findViewById(R.id.button3); Button b4 = (Button)findViewById(R.id.button4);
final EditText et1 = (EditText)findViewById(R.id.editText1); final EditText et2 = (EditText)findViewById(R.id.editText2); final EditText et3 = (EditText)findViewById(R.id.editText3);
final Geocoder geocoder = new Geocoder(this); b1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 위도,경도 입력 후 변환 버튼 클릭 List<Address> list = null; try { double d1 = Double.parseDouble(et1.getText().toString()); double d2 = Double.parseDouble(et2.getText().toString());
list = geocoder.getFromLocation( d1, // 위도 d2, // 경도 10); // 얻어올 값의 개수 } catch (IOException e) { e.printStackTrace(); Log.e("test", "입출력 오류 - 서버에서 주소변환시 에러발생"); } if (list != null) { if (list.size()==0) { tv.setText("해당되는 주소 정보는 없습니다"); } else { tv.setText(list.get(0).toString()); } } } });
b2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { List<Address> list = null;
String str = et3.getText().toString(); try { list = geocoder.getFromLocationName( str, // 지역 이름 10); // 읽을 개수 } catch (IOException e) { e.printStackTrace(); Log.e("test","입출력 오류 - 서버에서 주소변환시 에러발생"); }
if (list != null) { if (list.size() == 0) { tv.setText("해당되는 주소 정보는 없습니다"); } else { tv.setText(list.get(0).toString()); // list.get(0).getCountryName(); // 국가명 // list.get(0).getLatitude(); // 위도 // list.get(0).getLongitude(); // 경도 } } } });
b3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 위도,경도 입력 후 지도 버튼 클릭 => 지도화면으로 인텐트 날리기 double d1 = Double.parseDouble(et1.getText().toString()); double d2 = Double.parseDouble(et2.getText().toString());
int permissionCheck = ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_CALENDAR); if (permissionCheck == PackageManager.PERMISSION_DENIED) {