구글맵 API document
'프로그래밍 > Android (Java)' 카테고리의 다른 글
구글맵 줌버튼 위치 조정 (0) | 2019.06.27 |
---|---|
어플 아이콘 변경 (0) | 2019.06.25 |
구글 아이콘 무료 사용 가능 (0) | 2019.06.24 |
naverMap 을 전역 변수로 활용하기 (0) | 2019.06.07 |
안드로이드 개발 Android GPS 정보 알아오기 (0) | 2019.06.07 |
구글맵 줌버튼 위치 조정 (0) | 2019.06.27 |
---|---|
어플 아이콘 변경 (0) | 2019.06.25 |
구글 아이콘 무료 사용 가능 (0) | 2019.06.24 |
naverMap 을 전역 변수로 활용하기 (0) | 2019.06.07 |
안드로이드 개발 Android GPS 정보 알아오기 (0) | 2019.06.07 |
어플 아이콘 변경 (0) | 2019.06.25 |
---|---|
구글맵 API document (0) | 2019.06.25 |
naverMap 을 전역 변수로 활용하기 (0) | 2019.06.07 |
안드로이드 개발 Android GPS 정보 알아오기 (0) | 2019.06.07 |
Android 액티비티를 팝업(Popup)으로 띄우기, 데이터 주고받기 (0) | 2019.06.05 |
네이버 맵을 사용하려고 보면
아래와 같이 public void onCreate(Bundle savedInstanceState) 영역 바깥쪽에 아래 코드를 넣어야 하고,
onMapReady 안에서만 naverMap 을 사용할 수 있었다.
이것은 액티비티가 열릴때 자동 실행되는 부분으로 모든 효과나 설정을 onMapReady 안에서만 처리가 가능했다.
사용자가 값을 변경해서 요청할 경우에는 사용하지 못하게... ㅜ.ㅜ
@UiThread @Override public void onMapReady(@NonNull NaverMap naverMap) { naverMap.setMapType(NaverMap.MapType.Basic); // 지도 타입 naverMap.setLayerGroupEnabled(NaverMap.LAYER_GROUP_TRANSIT, true); // 오버레이되는 정보 (대중교통 - 버스, 지하철) // 지정된 좌표로 카메라 이동 CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.4685195, 126.8844555)) .animate(CameraAnimation.Easing, 2000); naverMap.moveCamera(cameraUpdate); } |
그래나 해결책을 찾았다. naverMap 을 전역 변수화 하면 다른곳에서도 사용이 가능하다.^^
public class MapActivity extends FragmentActivity implements OnMapReadyCallback { @Override
... (생략) ... CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5670135, 126.9783740)) .animate(CameraAnimation.Easing, 2000); ... (생략) ... }
// 네이버맵 초기 설정 |
[참고] https://nittaku.tistory.com/69
https://developers.google.com/maps/documentation/android-sdk/infowindows?hl=ko
구글맵 API document (0) | 2019.06.25 |
---|---|
구글 아이콘 무료 사용 가능 (0) | 2019.06.24 |
안드로이드 개발 Android GPS 정보 알아오기 (0) | 2019.06.07 |
Android 액티비티를 팝업(Popup)으로 띄우기, 데이터 주고받기 (0) | 2019.06.05 |
xml 파일로 말풍선 만들기 (0) | 2019.05.27 |
안드로이드에서 GPS 정보를 가져온 후 자기 위치를 MAP 에 표시하거나 다른 사람에게 위치 정보를 알릴 수도 있습니다. 앱에서 GPS 정보는 아주 다양하게 쓰이기 때문에 별도의 클래스를 만들어서 사용하는 것이 좋겠죠. 스마트폰에 GPS 설정이 되어 있지 않을 때 팝업창을 띄워서 설정창으로 이동할 수 있는 소스도 추가가 되어 있습니다. 그리고 최근에 수정한 내용 중 API 23 버전부터 퍼미션을 추가해야 되는 부분도 참고 하시기 바랍니다.
▼ 먼저 AndroidManifest.xml 에 GPS 정보를 가져올 수 있도록 환경을 셋팅해야 합니다.
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> |
▼ GPS 정보를 알아오는 클래스에 대해서 알아봅니다. 클래스명은 GpsInfo.java 입니다. 추상클래스 Service 와 위치정보를 받아오기 위한 Listener 인터페이스 클래스 LocationListener 상속합니다. 그리고 GPS나 네트워크 사용유무, 얼마에 한번씩 데이터를 업데이트 할 것인지에 대한 변수들을 만듭니다. 실질적으로 위치정보를 알아오는 클래스는 LocationManager 입니다. 이것도 변수지정해 놓습니다.
private final Context mContext;
// 현재 GPS 사용유무 boolean isGPSEnabled = false;
// 네트워크 사용유무 boolean isNetworkEnabled = false;
// GPS 상태값 boolean isGetLocation = false;
Location location; double lat; // 위도 double lon; // 경도
// 최소 GPS 정보 업데이트 거리 10미터 private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;
// 최소 GPS 정보 업데이트 시간 밀리세컨이므로 1분 private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1;
protected LocationManager locationManager; |
▼ 다음은 GPS 위치값을 가져오기 위한 함수입니다. LocationManager 을 사용하였으며 requestLocationUpdates() 함수로 현재 정보를 업데이트 하고 getLastKnownLocation()
함수로 위치값을 가져옵니다.
this.isGetLocation = true; // 네트워크 정보로 부터 위치값 가져오기 if (isNetworkEnabled) { locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null) { location = locationManager .getLastKnownLocation(LocationManager.NETWORK_PROVIDER); if (location != null) { // 위도 경도 저장 lat = location.getLatitude(); lon = location.getLongitude(); } } }
if (isGPSEnabled) { if (location == null) { locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this); if (locationManager != null) { location = locationManager .getLastKnownLocation(LocationManager.GPS_PROVIDER); if (location != null) { lat = location.getLatitude(); lon = location.getLongitude(); } } } } |
▼ 위 함수를 실행전에 GPS 상태정보와 네트워크 정보를 가져와 제대로 환경이 되어있지 않다면 정보를 가져오는 부분을 스킵하겠죠.
// GPS 정보 가져오기 isGPSEnabled = locationManager.isProviderEnabled( LocationManager.GPS_PROVIDER);
// 현재 네트워크 상태 값 알아오기 isNetworkEnabled = locationManager.isProviderEnabled( LocationManager.NETWORK_PROVIDER); |
▼ 이렇게 환경정보를 확인했는데 제대로 되어있지 않다면 GPS 정보가 제대로 설정 되어있는지 확인을 위한 alert 창을 띄우게 되고, 설정창으로 바로 가서 다시 GPS 를 사용할수 있도록 셋팅페이지로 가게 하는 기능입니다.
public void showSettingsAlert(){ AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
alertDialog.setTitle("GPS 사용유무셋팅"); alertDialog.setMessage("GPS 셋팅이 되지 않았을수도 있습니다. \n 설정창으로 가시겠습니까?"); // OK 를 누르게 되면 설정창으로 이동합니다. alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog,int which) { Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); mContext.startActivity(intent); } }); // Cancle 하면 종료 합니다. alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } });
alertDialog.show(); } |
▼ 안드로이드가 업그레이드 되면서 보안을 좀더 강화했는데 AndroidManifest.xml 에만 퍼미션을 넣어서는 안됩니다. 소스에서 사용자에게 퍼미션을 요청하는 로직을 넣어야 합니다. 그렇지 않으면 다음과 같은 에러가 발생합니다.
▼ 일단 GpsInfo.class 에 퍼미션 체크 로직을 넣어야 에러가 사라집니다.
if ( Build.VERSION.SDK_INT >= 23 && ContextCompat.checkSelfPermission( mContext, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission( mContext, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return null; } |
▼ 아래는 GPS 정보를 가져오기 위한 GpsInfo.java 의 전체 소스입니다.
import android.annotation.TargetApi; import android.app.AlertDialog; import android.app.Service; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.provider.Settings; import android.support.v4.content.ContextCompat;
public class GpsInfo extends Service implements LocationListener {
private final Context mContext;
// 현재 GPS 사용유무 boolean isGPSEnabled = false;
// 네트워크 사용유무 boolean isNetworkEnabled = false;
// GPS 상태값 boolean isGetLocation = false;
Location location; double lat; // 위도 double lon; // 경도
// 최소 GPS 정보 업데이트 거리 10미터 private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;
// 최소 GPS 정보 업데이트 시간 밀리세컨이므로 1분 private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1;
protected LocationManager locationManager;
public GpsInfo(Context context) { this.mContext = context; getLocation(); }
@TargetApi(23) public Location getLocation() { if ( Build.VERSION.SDK_INT >= 23 && ContextCompat.checkSelfPermission( mContext, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission( mContext, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return null; }
try { locationManager = (LocationManager) mContext .getSystemService(LOCATION_SERVICE);
// GPS 정보 가져오기 isGPSEnabled = locationManager .isProviderEnabled(LocationManager.GPS_PROVIDER);
// 현재 네트워크 상태 값 알아오기 isNetworkEnabled = locationManager .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGPSEnabled && !isNetworkEnabled) { // GPS 와 네트워크사용이 가능하지 않을때 소스 구현 } else { this.isGetLocation = true; // 네트워크 정보로 부터 위치값 가져오기 if (isNetworkEnabled) { locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null) { location = locationManager .getLastKnownLocation(LocationManager.NETWORK_PROVIDER); if (location != null) { // 위도 경도 저장 lat = location.getLatitude(); lon = location.getLongitude(); } } }
if (isGPSEnabled) { if (location == null) { locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this); if (locationManager != null) { location = locationManager .getLastKnownLocation(LocationManager.GPS_PROVIDER); if (location != null) { lat = location.getLatitude(); lon = location.getLongitude(); } } } } }
} catch (Exception e) { e.printStackTrace(); } return location; }
/** * GPS 종료 * */ public void stopUsingGPS(){ if(locationManager != null){ locationManager.removeUpdates(GpsInfo.this); } }
/** * 위도값을 가져옵니다. * */ public double getLatitude(){ if(location != null){ lat = location.getLatitude(); } return lat; }
/** * 경도값을 가져옵니다. * */ public double getLongitude(){ if(location != null){ lon = location.getLongitude(); } return lon; }
/** * GPS 나 wife 정보가 켜져있는지 확인합니다. * */ public boolean isGetLocation() { return this.isGetLocation; }
/** * GPS 정보를 가져오지 못했을때 * 설정값으로 갈지 물어보는 alert 창 * */ public void showSettingsAlert(){ AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
alertDialog.setTitle("GPS 사용유무셋팅"); alertDialog.setMessage("GPS 셋팅이 되지 않았을수도 있습니다. \n 설정창으로 가시겠습니까?");
// OK 를 누르게 되면 설정창으로 이동합니다. alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog,int which) { Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); mContext.startActivity(intent); } }); // Cancle 하면 종료 합니다. alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } });
alertDialog.show(); }
@Override public IBinder onBind(Intent arg0) { return null; }
public void onLocationChanged(Location location) { // TODO Auto-generated method stub
}
public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub
}
public void onProviderEnabled(String provider) { // TODO Auto-generated method stub
}
public void onProviderDisabled(String provider) { // TODO Auto-generated method stub
} } |
두 번째는 GPS 정보를 가져오는 Activity 에서의 퍼미션 체크 로직을 삽입해야 합니다. 기존에 없던 로직으로 callPermission() 함수가 그것입니다. 함수로 퍼미션 요청을 사용자에게 하면 그림과 같은 요청 팝업창이 뜹니다. 팝업창에서 DENY/ALLOW 하나를 선택하면 Override 한 onRequestPermissionsResult() 로 결과 값을 전달합니다.
▼ 이번에 추가한 callPermission() 와 onRequestPermissionsResult() 소스는 다음과 같습니다.
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == PERMISSIONS_ACCESS_FINE_LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
isAccessFineLocation = true;
} else if (requestCode == PERMISSIONS_ACCESS_COARSE_LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED){
isAccessCoarseLocation = true; }
if (isAccessFineLocation && isAccessCoarseLocation) { isPermission = true; } }
// 전화번호 권한 요청 private void callPermission() { // Check the SDK version and whether the permission is already granted or not. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions( new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_ACCESS_FINE_LOCATION);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
requestPermissions( new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSIONS_ACCESS_COARSE_LOCATION); } else { isPermission = true; } } |
▼ GPS 정보를 사용하는 메인 Activity 전체 소스입니다. Toast 를 이용해 화면에 위치 정보를 띄우고 TextView 에 위도와 경도를 알려줍니다.
import android.Manifest; import android.app.Activity; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast;
/** GPS 샘플 */ public class GpsActivity extends Activity {
private Button btnShowLocation; private TextView txtLat; private TextView txtLon; private final int PERMISSIONS_ACCESS_FINE_LOCATION = 1000; private final int PERMISSIONS_ACCESS_COARSE_LOCATION = 1001; private boolean isAccessFineLocation = false; private boolean isAccessCoarseLocation = false; private boolean isPermission = false;
// GPSTracker class private GpsInfo gps;
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_gps);
btnShowLocation = (Button) findViewById(R.id.btn_start); txtLat = (TextView) findViewById(R.id.tv_latitude); txtLon = (TextView) findViewById(R.id.tv_longitude);
// GPS 정보를 보여주기 위한 이벤트 클래스 등록 btnShowLocation.setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { // 권한 요청을 해야 함 if (!isPermission) { callPermission(); return; }
gps = new GpsInfo(GpsActivity.this); // GPS 사용유무 가져오기 if (gps.isGetLocation()) {
double latitude = gps.getLatitude(); double longitude = gps.getLongitude();
txtLat.setText(String.valueOf(latitude)); txtLon.setText(String.valueOf(longitude));
Toast.makeText( getApplicationContext(), "당신의 위치 - \n위도: " + latitude + "\n경도: " + longitude, Toast.LENGTH_LONG).show(); } else { // GPS 를 사용할수 없으므로 gps.showSettingsAlert(); } } });
callPermission(); // 권한 요청을 해야 함 }
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == PERMISSIONS_ACCESS_FINE_LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
isAccessFineLocation = true;
} else if (requestCode == PERMISSIONS_ACCESS_COARSE_LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED){
isAccessCoarseLocation = true; }
if (isAccessFineLocation && isAccessCoarseLocation) { isPermission = true; } }
// 전화번호 권한 요청 private void callPermission() { // Check the SDK version and whether the permission is already granted or not. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions( new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_ACCESS_FINE_LOCATION);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
requestPermissions( new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSIONS_ACCESS_COARSE_LOCATION); } else { isPermission = true; } } } |
API 23 버전부터 아래 에러가 난다면 두 가지 permission 을 추가해야 합니다. ACCESS_FINE_LOCATION 은 이미 있고 ACCESS_COARSE_LOCATION 만 추가하면 되겠죠.
Call requires permission which may be rejected by user. Code should explicitly check to see if permission is available.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> |
출처: https://mainia.tistory.com/1153 [녹두장군 - 상상을 현실로]
구글 아이콘 무료 사용 가능 (0) | 2019.06.24 |
---|---|
naverMap 을 전역 변수로 활용하기 (0) | 2019.06.07 |
Android 액티비티를 팝업(Popup)으로 띄우기, 데이터 주고받기 (0) | 2019.06.05 |
xml 파일로 말풍선 만들기 (0) | 2019.05.27 |
DialogFragment로 Custom Dialog 만들기 (0) | 2019.05.17 |
MainActivity.java
public class MainActivity extends AppCompatActivity {
TextView txtResult;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
txtResult = (TextView)findViewById(R.id.txtResult); }
//버튼 public void mOnPopupClick(View v){ //데이터 담아서 팝업(액티비티) 호출 Intent intent = new Intent(this, PopupActivity.class); intent.putExtra("data", "Test Popup"); startActivityForResult(intent, 1); }
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode==1){ if(resultCode==RESULT_OK){ //데이터 받기 String result = data.getStringExtra("result"); txtResult.setText(result); } } } } |
PopupActivity.java
public class PopupActivity extends Activity {
TextView txtText;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //타이틀바 없애기 requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.popup_activity);
//UI 객체생성 txtText = (TextView)findViewById(R.id.txtText);
//데이터 가져오기 Intent intent = getIntent(); String data = intent.getStringExtra("data"); txtText.setText(data); }
//확인 버튼 클릭 public void mOnClose(View v){ //데이터 전달하기 Intent intent = new Intent(); intent.putExtra("result", "Close Popup"); setResult(RESULT_OK, intent);
//액티비티(팝업) 닫기 finish(); }
@Override public boolean onTouchEvent(MotionEvent event) { //바깥레이어 클릭시 안닫히게 if(event.getAction()==MotionEvent.ACTION_OUTSIDE){ return false; } return true; }
@Override public void onBackPressed() { //안드로이드 백버튼 막기 return; } } |
* 10 : 타이틀바 없애기
* 17-18 : Intent 에서 data 가져오기
* 25-27 : Intent로 data 전달하기
* 34-40 : 바깥 레이어를 눌러도 닫히지 않게 하기
* 43-46 : 안드로이드 백버튼 막기
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="16dp" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:paddingBottom="8dp" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:text="액티비티를 팝업으로 띄우기" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
<LinearLayout android:paddingBottom="8dp" android:orientation="horizontal" android:gravity="center" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:text="팝업" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="mOnPopupClick"/> </LinearLayout>
<LinearLayout android:paddingBottom="8dp" android:orientation="horizontal" android:gravity="center" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/txtResult" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
</LinearLayout> |
popup_activity.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:background="#eeeeee" android:orientation="vertical" android:layout_width="300dp" android:layout_height="wrap_content">
<!-- 타이틀바 --> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:text="Notice" android:textSize="20sp" android:textColor="#fff" android:gravity="center" android:background="#ff7a00" android:layout_width="match_parent" android:layout_height="53dp" /> </LinearLayout> <!-- //end 타이틀바 -->
<!-- Notice --> <LinearLayout android:padding="24dp" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/txtText" android:textSize="15sp" android:textColor="#000" android:alpha="0.87" android:gravity="center" android:layout_marginBottom="3dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> <!-- Notice -->
<View android:background="#66bdbdbd" android:layout_width="match_parent" android:layout_height="1dp" />
<!-- 닫기 버튼 --> <LinearLayout android:orientation="horizontal" android:gravity="center" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:text="확인" android:textSize="15sp" android:textColor="#ff7a00" android:padding="16dp" android:gravity="center" android:background="#00000000" android:layout_width="match_parent" android:layout_height="53dp" android:onClick="mOnClose"/> </LinearLayout> <!--// 닫기 버튼 --> </LinearLayout> |
* 팝업의 가로세로 길이는 직접 정해줍니다
AndroidMenifest.xml
<!-- 팝업 Activity --> <activity android:name=".PopupActivity" android:theme="@android:style/Theme.Dialog" /> |
* Popup으로 띄울 Activity의 Theme를 바꿔줍니다
결과
* 팝업 호출(데이터 전달) -> 팝업에서 전달받은 데이터 보여줌 , 팝업 닫기(데이터 전달) -> 데이터 받아서 보여줌
출처: https://ghj1001020.tistory.com/9 [혁준 블로그]
naverMap 을 전역 변수로 활용하기 (0) | 2019.06.07 |
---|---|
안드로이드 개발 Android GPS 정보 알아오기 (0) | 2019.06.07 |
xml 파일로 말풍선 만들기 (0) | 2019.05.27 |
DialogFragment로 Custom Dialog 만들기 (0) | 2019.05.17 |
라디오버튼 사용하기 (0) | 2019.05.17 |
안드로이드에서 배경을 처리하기 위해서, 이미지나 컬러를 많이 사용한다.
그리고, res/drawable 폴더에 xml 파일을 만들어서 이미지처럼 사용할 수 도 있다.
이번 포스팅에서는 xml 파일 만을 이용하여, 아래와 같은 모양의 말풍선 layout 을 만들어보겠다.
화살표가 아래를 향하는 말풍선 구조는 이렇다.
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:clickable="true" >
<FrameLayout android:src="@drawable/speech_box"
android:layout_width="match_parent"
android:layout_height="100dip">
</FrameLayout>
<ImageView android:src="@drawable/down_arrow_nor"
android:layout_width="30dip"
android:layout_height="30dip"
android:layout_gravity="center_horizontal" />
</LinearLayout>
그림으로 보면 이런 구조
좌우, 위로 향하는 화살표 말풍선은 잘 배치하면 된다.
말풍선 안에 단순 텍스트 뿐 아니라 이미지를 배치하거나 다른 레이아웃, 뷰를 쉽게 추가하기 위해서, 말풍선 바디 부분은 FrameLayout 을 사용했다.
사실 이 글에서 다루고 싶었던 내용은 삼각형 모양의 화살표를 xml 파일로 만드는 것이다.
알고보면 원리는 간단하다.
사각형을 그린 뒤, 45도 회전시킨 후, x, y 축으로 적당히 이동시켜서, 한쪽 모서리만 그려지게 만들면 된다.
아래로 향하는 화살표를 만들기 위해, drawable 폴더에 down_arrow_nor.xml 파일을 하나 만들어서 아래와 같이 사각형을 그려주도록 하자.
<?xml version="1.0" encoding="utf-8"?>
<item>
<shape android:shape="rectangle" >
<solid android:color="#88FFFFFF"/>
<padding
android:left="0dip"
android:right="0dip"
android:top="0dip"
android:bottom="0dip"/>
</shape>
</item>
</layer-list>
레이아웃에 이미지뷰를 띄워서 확인해보면 아래 그림과 같이 사각형이 그려진다. (배경 컬러 : #555500)
이제 이 사각형을 오른쪽으로 45도 돌려주면 아래와 같이 8각형 모양으로 나타난다. 이는 내가 이미지뷰에 지정한 사이즈 (50dip x 50dip) 의 영역 밖에서 각 모서리 부분이 그려졌기 때문이다.
<?xml version="1.0" encoding="utf-8"?>
<item>
<rotate android:fromDegrees="45"
android:toDegrees="45">
<shape android:shape="rectangle" >
<solid android:color="#88FFFFFF"/>
<padding
android:left="0dip"
android:right="0dip"
android:top="0dip"
android:bottom="0dip"/>
</shape>
</rotate>
</item>
</layer-list>
이제 모서리 부분만 보이도록 이미지를 X, Y 축 방향으로 적당히 이동하면 된다.
그런데 여기서 주의할 점은, 이미지 회전 시 X,Y 축도 같이 45도 틀어졌다는 것이다.
그래서, X 축 방향으로만, 혹은 Y 축 방향으로만 움직인다고 해서 모서리만 보이거나 하지 않는다. 두 축에 대해 모두 이동을 해야 한다.
여러번 해보면서 자신이 생각하는 모양에 맞게 맞춰나가는게 좋다.
내가 사용한 값은 이렇다.
<?xml version="1.0" encoding="utf-8"?>
<item>
<rotate
android:fromDegrees="45"
android:toDegrees="45"
android:pivotX="135%"
android:pivotY="13%" >
<shape android:shape="rectangle" >
<solid android:color="#88FFFFFF"/>
<padding
android:left="0dip"
android:right="0dip"
android:top="0dip"
android:bottom="0dip"/>
</shape>
</rotate>
</item>
</layer-list>
출처: https://bbulog.tistory.com/19 [뿔로그]
안드로이드 개발 Android GPS 정보 알아오기 (0) | 2019.06.07 |
---|---|
Android 액티비티를 팝업(Popup)으로 띄우기, 데이터 주고받기 (0) | 2019.06.05 |
DialogFragment로 Custom Dialog 만들기 (0) | 2019.05.17 |
라디오버튼 사용하기 (0) | 2019.05.17 |
구글맵 (GoogleMap) 출력을 위한 인증 코드 생성, 활용 (0) | 2019.05.14 |
이번 포스팅에서는 안드로이드에서 기본 제공하는 다이얼로그가 아닌 커스텀 다이얼로그를 적용하면서 삽질 했던 내용에 대해서 써 보려고 한다.
만들고자 하는 모양은 아래와 같다. 이전에 포스팅한 라운드 및 그라데이션 처리된 나인패치 이미지가 적용된 다이얼로그이다.
하단의 스샷 처럼 라디오 버튼 [동의], [미동의] 선택값을 다이얼로그에 뿌려주는 것 까지 다루려고 한다. 하지만 목적은 커스텀 다이얼로그의 구현이고, 또 귀차니즘으로 인해 결과물의 폰트나 컬러, 버튼 등은 똑같이 구현 하지는 않으려고하니 많은 양해를 바란다. ㅠㅠ
참, 이 블로그의 포스팅 목적은 개발 초보인 본인의 삽질 방지를 위한 기록에 초점이 맞춰져 있으니, 잘못된 부분이 분명 있을 수 있고, 더 심플하고, 효율적이고 방법들이 얼마든지 있을 수 있다.그러한 부분들을 번거로움을 무릅쓰고 공유를 해 주신다면 감사히 받겠습니다.(편의상 반말로 쭉~ 갈 건데.. 왠지 여기서는 존댓말을 써야....)
여튼 이제 본론으로 들어가자.
다이얼로그를 커스텀하려니 막막함에 자연스레 검색을 하게 됐다. android custom dialog 라는 키워드로 구글에 검색을 해보면..
1. Dialog를 이용하는 방법
2. AlertDialog.Builder를 이용하는 방법
3. DialogFragment를 이용하는 방법
이렇게 3가지를 주로 찾을 수 있었다. 뭐야.. 뭐가 더 좋은거야...
검색을 계속 해보니 Android Developer 공식 홈에서 대화상자 페이지를 보니 뭘 써야 할지 알 수 있었다.
해당 내용은...
Dialog 클래스가 대화상자의 기본 클래스이지만, Dialog를 직접 인스턴스화하는 것은 삼가야 합니다. 대신 다음 서브클래스 중 하나를 사용하세요.
AlertDialog : 제목 하나, 최대 세 개의 버튼, 선택 가능한 품목 목록 또는 사용자 지정 레이아웃을 표시할 수 있는 대화상자입니다.DatePickerDialog 또는 TimePickerDialog : 미리 정의된 UI가 있는 대화상자로 사용자로 하여금 날짜 또는 시간을 선택할 수 있게 해줍니다.
이러한 클래스가 대화상자의 스타일과 구조를 정의하지만, 대화상자의 컨테이너로는 DialogFragment를 사용해야 합니다. DialogFragment 클래스는 대화상자를 만들고 그 외관을 관리하는 데 필요한 모든 컨트롤을 제공합니다. Dialog 객체에서 메서드를 호출하는 것 대신입니다.
대화상자를 관리하기 위해 DialogFragment를 사용하면 사용자가 Back 버튼을 누르거나 화면을 돌릴 때 등 수명 주기 이벤트를 올바르게 처리하도록 보장할 수 있습니다. DialogFragment 클래스를 사용하면 대화상자의 UI를 더 큰 UI에 포함시킬 수 있는 구성 요소로 재사용할 수도 있습니다. 이것은 기존의 Fragment와 똑같습니다(대화상자 UI를 크고 작은 화면에서 서로 다르게 나타나도록 하고자 하는 경우 등).
이렇게나 추천하니 써봐야겠다.
그래서 작성해 본 코드다.
- MainActivity에서 동의/미동의 선택에 따른 CustomDialogFragment를 실행하는 부분이다.
RadioGroup radioGroup = (RadioGroup)findViewById(R.id.radio_group);radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) { String agreeOrDisagree = null; if (checkedId == R.id.radio_group) { agreeOrDisagree = getString(R.string.radio_agree); } else { agreeOrDisagree = getString(R.string.radio_disagree); } CustomDialogFragment dialog = CustomDialogFragment.newInstance( getString(R.string.custom_dialog_msg, agreeOrDisagree) ); dialog.show(getSupportFragmentManager(), "dialog"); } });
CustomDialogFragment의 instance를 생성할때 resource의 string을 전달해줬는데,
<string name="radio_agree">동의</string><string name="radio_disagree">미동의</string><string name="custom_dialog_msg"> 마케팅 정보 수신 %1$s 처리가 완료되었습니다. </string>
이런식으로 구성되어 있으며, %1$s 부분을 변수 처럼 getString을 통해 넘기는 인자값을 매핑해서 사용 할 수 있다. 만약 더 추가 적인 변수가 필요하다면, %1$s, %2$s, %3$s 이런식으로 string값에 넣어두고, 그 갯수에 맞게 인자값도 콤마로 구분지어서 던져 주면 된다.
- CustomDialogFragment 부분이다.
public class CustomDialogFragment extends DialogFragment implements View.OnClickListener{ private static final String TAG = "CustomDialogFragment"; private static final String ARG_DIALOG_MAIN_MSG = "dialog_main_msg"; private String mMainMsg; public static CustomDialogFragment newInstance(String mainMsg) { Bundle bundle = new Bundle(); bundle.putString(ARG_DIALOG_MAIN_MSG, mainMsg); CustomDialogFragment fragment = new CustomDialogFragment(); fragment.setArguments(bundle); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mMainMsg = getArguments().getString(ARG_DIALOG_MAIN_MSG); } } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); View view = getActivity().getLayoutInflater().inflate(R.layout.layout_custom_dialog, null); ((TextView)view.findViewById(R.id.dialog_confirm_msg)).setText(mMainMsg); view.findViewById(R.id.dialog_confirm_btn).setOnClickListener(this); builder.setView(view); return builder.create(); } private void dismissDialog() { this.dismiss(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.dialog_confirm_btn: dismissDialog(); break; } } }
잉... 코드를 여기다 붙여 넣으니 원하는 만큼 잘 표시해 주지 못하는 것 같다. gist나 그런걸로 별도로 빼야 할 거 같다. 뭐여튼..
실행 시켜 보면 아래와 같이 보인다.
또 검색 검색.. 이것저것 해보면서 xml에서 속성이나 style도 건드려 봤지만, 자바 코드로 하는게 가장 확실한거 같다. 그래서 onCreateDialog에서 Dialog를 리턴하기 전에 아래와 같이 수정 해준다.
Dialog dialog = getDialog();dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));dialog.setCanceledOnTouchOutside(false);
setBackgroundDrawable로 전에 모서리 부분에 표시되던 기본 백그라운드를 투명으로 바꿔 표시되지 않게 했고, setCanceledOnTouchOutside는 말 그대로 다이얼로그 바깥부분 터치를 통한 닫기 여부의 설정이다.
그 뒤의 결과물은 아래와 같다.
다 됐다~ .. 됐나? 싶었다. 근데 좀 이상하다. width값이 내가 지정한대로 먹지 않는 듯한 느낌적인 느낌.
그래서 10dp를 때리고 실행 시켜봤더니, 역시나... width값이 먹질 않는다.ㅠㅠ
또 검색 검색.. 미천한 영어와 실력으로 인해 삽질삽질.... 그러다 발견한 글.
1. onResume()에 width와 height를 resource의 dimes값을 자바 코드로 불러와 설정을 하고,
2. 다이얼로그의 layout을 RelativeLayout으로 설정한 뒤, width, height를 match_parent로 줘야한다.
라는 내용이었다. 그래서 작성한 onResume()과 그 결과다.
@Overridepublic void onResume() { super.onResume(); int dialogWidth = getResources().getDimensionPixelSize(R.dimen.dialog_fragment_width); int dialogHeight = ActionBar.LayoutParams.WRAP_CONTENT; getDialog().getWindow().setLayout(dialogWidth, dialogHeight);}
허허 잘된다.
매번 느끼지만 스택오버플로우 없으면 개발을 어찌하나 싶다..ㅋㅋ
끝.
* 추가적으로 onCreateDialog에서 AlertDialog.Builder를 사용하지 않고 onCreateView를 사용해서 같은 결과를 낼 수도 있다.
@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.layout_custom_dialog, container, false); ((TextView)view.findViewById(R.id.dialog_confirm_msg)).setText(mMainMsg); view.findViewById(R.id.dialog_confirm_btn).setOnClickListener(this); Dialog dialog = getDialog(); dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); dialog.setCanceledOnTouchOutside(false); return view;}
onCreateDialog 부분을 지우고 위의 코드를 넣어도 잘 나온다. 무슨 차이가 있는지는 정확하게 파악은 못 했다.
* 해당 소스를 깃헙의 gist를 통해 올려놨고, 아래에 첨부하니 참고하시기 바란다.
<?xml version="1.0" encoding="utf-8"?> |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
android:layout_width="match_parent" |
android:layout_height="match_parent"> |
<LinearLayout |
android:layout_width="match_parent" |
android:layout_height="match_parent" |
android:orientation="vertical" |
android:paddingLeft="20dp" |
android:paddingRight="20dp" |
android:paddingTop="30dp"> |
<LinearLayout |
android:layout_width="match_parent" |
android:layout_height="wrap_content" |
android:orientation="horizontal"> |
<TextView |
android:id="@+id/terms_tv_sub_title" |
android:layout_width="wrap_content" |
android:layout_height="wrap_content" |
android:layout_gravity="center_vertical" |
android:text="서브타이틀 표시 영역" |
android:textSize="12dp" /> |
<RadioGroup |
android:id="@+id/radio_group" |
android:layout_width="wrap_content" |
android:layout_height="wrap_content" |
android:layout_marginLeft="20dp" |
android:orientation="horizontal" |
android:textSize="12dp" |
android:visibility="visible"> |
<RadioButton |
android:id="@+id/radio_agree" |
android:layout_width="wrap_content" |
android:layout_height="wrap_content" |
android:text="@string/radio_agree" /> |
<RadioButton |
android:id="@+id/radio_disagree" |
android:layout_width="wrap_content" |
android:layout_height="wrap_content" |
android:text="@string/radio_disagree" /> |
</RadioGroup> |
</LinearLayout> |
<TextView |
android:id="@+id/terms_tv_detail_contents" |
android:layout_width="match_parent" |
android:layout_height="match_parent" |
android:layout_marginTop="30dp" |
android:text="약관 전문 표시 영역" |
android:textSize="12dp" /> |
</LinearLayout> |
</RelativeLayout> |
view rawactivity_main.xml hosted with ❤ by GitHub
public class CustomDialogFragment extends DialogFragment implements View.OnClickListener{ |
private static final String TAG = "CustomDialogFragment"; |
private static final String ARG_DIALOG_MAIN_MSG = "dialog_main_msg"; |
private String mMainMsg; |
public static CustomDialogFragment newInstance(String mainMsg) { |
Bundle bundle = new Bundle(); |
bundle.putString(ARG_DIALOG_MAIN_MSG, mainMsg); |
CustomDialogFragment fragment = new CustomDialogFragment(); |
fragment.setArguments(bundle); |
return fragment; |
} |
@Override |
public void onCreate(Bundle savedInstanceState) { |
super.onCreate(savedInstanceState); |
if (getArguments() != null) { |
mMainMsg = getArguments().getString(ARG_DIALOG_MAIN_MSG); |
} |
} |
@Override |
public void onResume() { |
super.onResume(); |
int dialogWidth = getResources().getDimensionPixelSize(R.dimen.dialog_fragment_width); |
int dialogHeight = ActionBar.LayoutParams.WRAP_CONTENT; |
getDialog().getWindow().setLayout(dialogWidth, dialogHeight); |
} |
@Override |
public Dialog onCreateDialog(Bundle savedInstanceState) { |
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); |
View view = getActivity().getLayoutInflater().inflate(R.layout.layout_custom_dialog, null); |
((TextView)view.findViewById(R.id.dialog_confirm_msg)).setText(mMainMsg); |
view.findViewById(R.id.dialog_confirm_btn).setOnClickListener(this); |
builder.setView(view); |
Dialog dialog = builder.create(); |
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); |
dialog.setCanceledOnTouchOutside(false); |
return dialog; |
} |
/* |
@Override |
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { |
View view = inflater.inflate(R.layout.layout_custom_dialog, container, false); |
((TextView)view.findViewById(R.id.dialog_confirm_msg)).setText(mMainMsg); |
view.findViewById(R.id.dialog_confirm_btn).setOnClickListener(this); |
Dialog dialog = getDialog(); |
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); |
dialog.setCanceledOnTouchOutside(false); |
return view; |
} |
*/ |
private void dismissDialog() { |
this.dismiss(); |
} |
@Override |
public void onClick(View v) { |
switch (v.getId()) { |
case R.id.dialog_confirm_btn: |
dismissDialog(); |
break; |
} |
} |
} |
view rawCustomDialogFragment.java hosted with ❤ by GitHub
<?xml version="1.0" encoding="utf-8"?> |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
android:layout_width="match_parent" |
android:layout_height="match_parent" |
android:background="@drawable/ninepatch_common_box_gray" |
android:padding="20dp"> |
<TextView |
android:id="@+id/dialog_confirm_msg" |
android:layout_width="match_parent" |
android:layout_height="wrap_content" |
android:layout_alignParentTop="true" |
android:gravity="center_horizontal" |
android:textSize="13sp" |
android:textColor="#111111" |
android:textStyle="bold" /> |
<Button |
android:id="@+id/dialog_confirm_btn" |
android:layout_width="66dp" |
android:layout_height="wrap_content" |
android:layout_below="@+id/dialog_confirm_msg" |
android:layout_centerHorizontal="true" |
android:layout_marginTop="15dp" |
android:background="@null" |
android:text="확인" |
android:textSize="12dp" /> |
</RelativeLayout> |
view rawlayout_custom_dialog.xml hosted with ❤ by GitHub
public class MainActivity extends AppCompatActivity { |
@Override |
protected void onCreate(Bundle savedInstanceState) { |
super.onCreate(savedInstanceState); |
setContentView(R.layout.activity_main); |
RadioGroup radioGroup = (RadioGroup)findViewById(R.id.radio_group); |
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { |
@Override |
public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) { |
String agreeOrDisagree = null; |
if (checkedId == R.id.radio_group) { |
agreeOrDisagree = getString(R.string.radio_agree); |
} else { |
agreeOrDisagree = getString(R.string.radio_disagree); |
} |
CustomDialogFragment dialog = CustomDialogFragment.newInstance( |
getString(R.string.custom_dialog_msg, agreeOrDisagree) |
); |
dialog.show(getSupportFragmentManager(), "dialog"); |
} |
}); |
} |
} |
view rawMainActivity.java hosted with ❤ by GitHub
공유
[출처] http://darrenkwon.blogspot.com/2017/04/dialogfragment-custom-dialog.html
Android 액티비티를 팝업(Popup)으로 띄우기, 데이터 주고받기 (0) | 2019.06.05 |
---|---|
xml 파일로 말풍선 만들기 (0) | 2019.05.27 |
라디오버튼 사용하기 (0) | 2019.05.17 |
구글맵 (GoogleMap) 출력을 위한 인증 코드 생성, 활용 (0) | 2019.05.14 |
ScaleAnimation 사용하기 (0) | 2019.05.09 |
안드로이드 : 라디오버튼 RadioButton 예제1
라디오버튼(RadioButton) 들은 하나의 그룹으로 묶여서 그룹내에서는 오직 한개만 선택할수 있게 해야 한다.
체크박스와 달리 라디오 그룹은 RadioGroup 으로 그룹 전체를 등록한다
RadioButton 은 각각 선언하는 것이 아니라 RadioGroup 으로 선언해서 사용한다.
activity_main.xml
http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" >
<TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="2015 최고의 걸그룹은?" android:textAppearance="?android:attr/textAppearanceLarge" />
<RadioGroup android:id="@+id/radioGroup1" android:layout_width="wrap_content" android:layout_height="wrap_content" >
<RadioButton android:id="@+id/radio0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="소녀시대" />
<RadioButton android:id="@+id/radio1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="2NE1" />
<RadioButton android:id="@+id/radio2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="씨스타" />
<RadioButton android:id="@+id/radio3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="걸스데이" />
<RadioButton android:id="@+id/radio4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="에이핑크" />
<RadioButton android:id="@+id/radio5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="AOA" />
<Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="선택완료" />
<TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="결과창" android:textAppearance="?android:attr/textAppearanceLarge" /> |
MainActivity.java
public class MainActivity extends ActionBarActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
// 체크박스와 달리 라디오 그룹은 그룹 전체를 등록한다 // RadioButton 은 각각 선언하는 것이 아니라 RadioGroup 으로 선언해서 사용한다.
final RadioGroup rg = (RadioGroup)findViewById(R.id.radioGroup1); Button b = (Button)findViewById(R.id.button1); final TextView tv = (TextView)findViewById(R.id.textView2); b.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) { int id = rg.getCheckedRadioButtonId(); //getCheckedRadioButtonId() 의 리턴값은 선택된 RadioButton 의 id 값. RadioButton rb = (RadioButton) findViewById(id); tv.setText("결과: " + rb.getText().toString()); } // end onClick() }); // end Listener
} // end onCreate
} // end Main |
실행화면
출처: https://bitsoul.tistory.com/47 [Happy Programmer~]
xml 파일로 말풍선 만들기 (0) | 2019.05.27 |
---|---|
DialogFragment로 Custom Dialog 만들기 (0) | 2019.05.17 |
구글맵 (GoogleMap) 출력을 위한 인증 코드 생성, 활용 (0) | 2019.05.14 |
ScaleAnimation 사용하기 (0) | 2019.05.09 |
Custom listview (Parse JSON And URL Images) - 웹 이미지 (0) | 2019.04.30 |
아래 두개 웹페이지만 참고해도 적용이 가능합니다.
https://mailmail.tistory.com/17
https://webnautes.tistory.com/647
=== 실제 작업 순서 ===
https://console.firebase.google.com/ 에서 해당 프로젝트 선택 후
좌측 상단의 '톱니바퀴' 모양 클릭 > '사용자 및 권한' 선택
[일반] 탭 선택 후 하단의 'SHA 인증서 지문' 에 '디지털 지문 추가' 선택
윈도우즈 cmd 에서 아래 명령으로 출력된 SHA-1 부분을 복사, 붙여넣고 생성하기
cd C:\Program Files\Android\Android Studio\jre\bin
keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
프로젝트 상세 내용 변경 되었으므로 google-services.json 파일 새로 갱신 (다운로드, 적용)
https://console.developers.google.com/apis/dashboard 에서 해당 프로젝트 선택 후 (맨위)
'+ API 및 서비스 사용 설정' 을 눌러 'Maps SDK for Android' 검색, 사용 설정
[사용자 인증 정보] 탭 선택 후 '사용자 인증 정보 만들기'.. 위에 API 관리자의 사용자 인증 정보 링크 부분 타고 들어감
상단에 다시 '사용자 인증 정보 만들기' 선택 후 출력된 'API 키' 선택
- 애플리케이션 제한 사항 : Android
- Android 앱의 사용량 제한 : firebase 에서 생성한 프로젝트명 (예: kr.itlog.makchatime) 과 SHA-1 키입력
- API 제한 사항 : 키제한 ('Maps SDK for Android' 선택)
- SAVE
개발중인 AndroidManifest.xml 파일의 <application> 안에 아래 내용 추가
---------------
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyD.......키 보안상 생략........CoLOlk" />
---------------
이제 준비가 되었으므로 예제 소스코드를 검색, 적용하여 확인하면 됩니다.
*참고로 화면이 하얗게 뜨는것은 인증이 되지 않아서 이므로 위 과정을 다시 살펴봐야 함.
DialogFragment로 Custom Dialog 만들기 (0) | 2019.05.17 |
---|---|
라디오버튼 사용하기 (0) | 2019.05.17 |
ScaleAnimation 사용하기 (0) | 2019.05.09 |
Custom listview (Parse JSON And URL Images) - 웹 이미지 (0) | 2019.04.30 |
커스텀 리스트뷰 (Custom ListView) - 로컬 이미지 + 텍스트 (ArrayList) (0) | 2019.04.24 |
이미지나 막대그래프 등이 늘어나고 줄어드는 등의 효과를 보여줄 수 있습니다.
layout 에서 적용
https://bitsoul.tistory.com/82
source 에서 적용
https://bitsoul.tistory.com/83
라디오버튼 사용하기 (0) | 2019.05.17 |
---|---|
구글맵 (GoogleMap) 출력을 위한 인증 코드 생성, 활용 (0) | 2019.05.14 |
Custom listview (Parse JSON And URL Images) - 웹 이미지 (0) | 2019.04.30 |
커스텀 리스트뷰 (Custom ListView) - 로컬 이미지 + 텍스트 (ArrayList) (0) | 2019.04.24 |
RelativeLayout 과 view 정렬의 실 사용 예 (0) | 2019.04.23 |
https://demonuts.com/android-parse-json-and-show-in-listview/
* 소스 말고 포스팅 글을 가지고 셋팅한다면 중간에 오타를 잘 살펴볼것
- 레이아웃명 : lv_players
- 소스에서 연결 : lv_player
* 예제는 해외 url 을 가져오므로 느림. 국내 서버에 json 파일과 이미지를 링크시키면 빠름
* 리스트뷰 아이템 클릭시 이벤트 발생 시키고 싶을 경우 아래 소스를 TennisAdapter.java 파일의
return convertView; 바로 위에 넣고 상황에 맞게 수정해 쓸 것.
// 넘버링 final int pos = position; // 위젯에 대한 이벤트 리스너 holder.iv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(context, "이미지 선택 " + pos, Toast.LENGTH_SHORT).show(); } }); holder.tvname.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(context, "이름 선택 " + pos, Toast.LENGTH_SHORT).show(); } }); holder.tvcountry.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(context, "나라 선택 " + pos, Toast.LENGTH_SHORT).show(); } }); holder.tvcity.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(context, "도시 선택 " + pos, Toast.LENGTH_SHORT).show(); } }); |
구글맵 (GoogleMap) 출력을 위한 인증 코드 생성, 활용 (0) | 2019.05.14 |
---|---|
ScaleAnimation 사용하기 (0) | 2019.05.09 |
커스텀 리스트뷰 (Custom ListView) - 로컬 이미지 + 텍스트 (ArrayList) (0) | 2019.04.24 |
RelativeLayout 과 view 정렬의 실 사용 예 (0) | 2019.04.23 |
스피너 사용하기 (셀렉트박스 selectbox, 풀다운 메뉴) (0) | 2019.04.23 |