플로팅 액션 버튼 (Floating Action Button)

프로그래밍/Android (Java)|2020. 1. 22. 11:33
반응형

In previous 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 from Inbox 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 by Dmytro Tarianyk Clans. It's very simple to implement and solving this problem quickly!
    DEMO VIDEO:

 

 

Import the library

    Adding this dependency to your application level build.gradle:
dependencies { compile 'com.github.clans:fab:1.6.4' }     Now, we have two objects called FloatingActionMenu and FloatingActionButton to build this layout.

Some important features

   FloatingActionMenu has 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).
  • menu_openDirection: Open menu up or down.

Usages in activity

Declaring a layout for our activity like this:

activity_main.xml

 

    <com.github.clans.fab.FloatingActionMenu
        android:id="@+id/fab_menu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:paddingBottom="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        fab:menu_backgroundColor="#ccffffff"
        fab:menu_fab_label="Choose an action"
        fab:fab_colorNormal="#DA4336"
        fab:fab_colorPressed="#E75043"
        fab:fab_colorRipple="#99FFFFFF"
        fab:fab_showShadow="true"
        fab:menu_labels_colorNormal="#333333"
        fab:menu_labels_colorPressed="#444444"
        fab:menu_labels_colorRipple="#66FFFFFF"
        fab:menu_labels_showShadow="true"
        fab:menu_labels_maxLines="-1"
        fab:menu_labels_position="left"
        fab:menu_openDirection="up"
        fab:fab_shadowColor="#66000000"
        fab:menu_labels_ellipsize="end"
        fab:menu_labels_singleLine="true">

        <com.github.clans.fab.FloatingActionButton
            android:id="@+id/fab1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@android:drawable/ic_menu_edit"
            fab:fab_label="Edit an item"
            fab:fab_size="mini" />

        <com.github.clans.fab.FloatingActionButton
            android:id="@+id/fab2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@android:drawable/ic_menu_add"
            fab:fab_label="Menu item 2"
            fab:fab_size="mini" />

        <com.github.clans.fab.FloatingActionButton
            android:id="@+id/fab3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@android:drawable/ic_menu_delete"
            fab:fab_label="@string/lorem_ipsum"
            fab:fab_size="mini" />

    </com.github.clans.fab.FloatingActionMenu>

 


MainActivity.java

 

package info.devexchanges.floatingactionmenu;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.github.clans.fab.FloatingActionButton;
import com.github.clans.fab.FloatingActionMenu;

public class MainActivity extends AppCompatActivity {

    private FloatingActionMenu fam;
    private FloatingActionButton fabEdit, fabDelete, fabAdd;

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

        fabAdd = (FloatingActionButton) findViewById(R.id.fab2);
        fabDelete = (FloatingActionButton) findViewById(R.id.fab3);
        fabEdit = (FloatingActionButton) findViewById(R.id.fab1);
        fam = (FloatingActionMenu) findViewById(R.id.fab_menu);

        //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);
                }
            }
        });
    }

    private View.OnClickListener onButtonClick() {
        return new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (view == fabAdd) {
                    showToast("Button Add clicked");
                } else if (view == fabDelete) {
                    showToast("Button Delete clicked");
                } else {
                    showToast("Button Edit clicked");
                }
                fam.close(true);
            }
        };
    }

    private void showToast(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }
}

 

 

    Running application, we'll have this output:

    Click the "representative button" to open Menu:

    After click the "delete button" in Menu:

    Animation for expanding/collapsing process:

 

Conclusions

    As you can see, with a small third-party library, we can build a FAM easily. By searching on Internet, you can find out another similar libraries:

    You should try to use them and choose the best one!
    Reference to the libary Github page: https://github.com/Clans/FloatingActionButton

 View project on Github

 

 

[출처] http://www.devexchanges.info/2016/07/floating-action-menu-in-android.html

반응형

댓글()

레이어가 겹칠때 하단 레이어는 터치 비활성화 시키기

프로그래밍/Android (Java)|2019. 12. 24. 08:33
반응형

레이어가 겹치게 되면 경우에 따라 상단 또는 하단 레이어가 터치 됩니다.

하단에 가려진 레이어를 터치되지 않도록 하려면 아래와 같이 하는 방법이 있습니다.

 

아래와 같이 layout 을 꾸미게 되면 3번 레이어가 최상단에 올라옵니다.

 

1번 레이어

2번 레이어

3번 레이어

 

이때 3번 레이어에 setClickable(true);  를 설정 합니다.

 

 

반응형

댓글()

어플에 애드몹 광고 넣기 예제

프로그래밍/Android (Java)|2019. 12. 20. 14:23
반응형

예제 소스 배포

https://github.com/googleads/googleads-mobile-android-examples/tree/master/java/admob

 

예제 소스 다운로드

https://github.com/googleads/googleads-mobile-android-examples/archive/master.zip

 

압축 파일 다운로드 후 원하는 광고 방식의 소스를 활용하면 됩니다.

 

----------

 

안드로이드에서 설명하는 예제 (쉬움)

https://developers.google.com/admob/android/quick-start

 

----------

 

반응형

댓글()

커스텀 스피너 (Custom Spinner)

프로그래밍/Android (Java)|2019. 10. 29. 15:19
반응형

1. 레이아웃 추가


<Spinner

    android:id="@+id/simpleSpinner"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:layout_centerHorizontal="true" /> 



2. custom_spinner_items.xml 레이아웃 생성


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:orientation="horizontal">


    <ImageView

        android:id="@+id/imageView"

        android:layout_width="50dp"

        android:layout_height="50dp"

        android:padding="5dp"

        android:src="@drawable/ic_launcher" />


    <TextView

        android:id="@+id/textView"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:layout_gravity="center"

        android:text="Demo"

        android:textColor="#000" />

</LinearLayout> 



3. 스피너 추가할 화면의 java 파일


public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener{



    String[] countryNames={"India","China","Australia","Portugle","America","New Zealand"};

    int flags[] = {R.drawable.india, R.drawable.china, R.drawable.australia, R.drawable.portugle, R.drawable.america, R.drawable.new_zealand};


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);


        Spinner spin = (Spinner) findViewById(R.id.simpleSpinner);

        spin.setOnItemSelectedListener(this);


        CustomAdapter customAdapter=new CustomAdapter(getApplicationContext(),flags,countryNames);

        spin.setAdapter(customAdapter);

    }



    @Override

    public void onItemSelected(AdapterView<?> arg0, View arg1, int position,long id) {

        Toast.makeText(getApplicationContext(), countryNames[position], Toast.LENGTH_LONG).show();

    }


    @Override

    public void onNothingSelected(AdapterView<?> arg0) {

        // TODO Auto-generated method stub

    }

} 



4. CustomAdapter.java 생성


import android.content.Context;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.ImageView;

import android.widget.TextView;


public class CustomAdapter extends BaseAdapter {

    Context context;

    int flags[];

    String[] countryNames;

    LayoutInflater inflter;


    public CustomAdapter(Context applicationContext, int[] flags, String[] countryNames) {

        this.context = applicationContext;

        this.flags = flags;

        this.countryNames = countryNames;

        inflter = (LayoutInflater.from(applicationContext));

    }


    @Override

    public int getCount() {

        return flags.length;

    }


    @Override

    public Object getItem(int i) {

        return null;

    }


    @Override

    public long getItemId(int i) {

        return 0;

    }


    @Override

    public View getView(int i, View view, ViewGroup viewGroup) {

        view = inflter.inflate(R.layout.custom_spinner_items, null);

        ImageView icon = (ImageView) view.findViewById(R.id.imageView);

        TextView names = (TextView) view.findViewById(R.id.textView);

        icon.setImageResource(flags[i]);

        names.setText(countryNames[i]);

        return view;

    }

} 



[출처] https://abhiandroid.com/ui/custom-spinner-examples.html

반응형

댓글()

ImageView 모서리 둥글게 하기

프로그래밍/Android (Java)|2019. 10. 29. 14:30
반응형

이미지뷰 모서리를 둥글게 하는 방법으러 java 에서 처리하는 방법도 있지만 간단히 레이아웃에서 처리하는 방법도 있어 방법을 설명합니다.



1. app 단의 build.gradle 수정


implementation 'androidx.cardview:cardview:1.0.0'    // androidx 의 경우

또는

implementation 'com.android.support:cardview-v7:28.0.0' 


수정시 우측 상단에 뜨는 Sync 버튼 클릭



2. layout 수정


ImageView 를 감싸는 CardView 를 만들어 줍니다.


<androidx.cardview.widget.CardView    // androidx 의 경우

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        app:cardCornerRadius="5dp">


    <ImageView

        android:id="@+id/iv"

        android:src="@drawable/sysdocu_img"

        android:layout_width="50dp"

        android:layout_height="50dp"

        android:scaleType="fitXY"/>


</androidx.cardview.widget.CardView> 


* androidx 가 아닌 경우 아래 것으로 사용합니다.

<android.support.v7.widget.CardView

    ....>

    <ImageView

        ..../>

</android.support.v7.widget.CardView>



반응형

댓글()

웹 브라우저 링크로 앱 실행 방법 (유사 딥링크, 동적링크)

프로그래밍/Android (Java)|2019. 9. 30. 11:18
반응형

안드로이드 자체 브라우저로 특정 앱을 실행 하는 것이 가능하다.

이것은 안드로이드 OS가 가진 intent의 특징으로 가능 한것 같다.

Intent 의 자세한 내용은 안드로이드 API Guide에 있는  Intents and Intent Filters 를 보면 알수 있다.


1. 먼저 실행 하고자 하는 앱의 AndroidManifest.xml 파일에서 실행하고자 하는 Activity아래에 Intent-filter를 선언해준다.


<activity android:name="SearchActionActivity">
             <intent-filter>  
                <action android:name="android.intent.action.VIEW"/>  
                <category android:name="android.intent.category.DEFAULT"/>  
                <category android:name="android.intent.category.BROWSABLE"/>  
                <data android:scheme="callMyApp" android:host="search"/>  
            </intent-filter>
</activity>


2. 웹 브라우저 상에서 링크 설정 방법
- 웹에서 특정 URL형태로 설정을 해줘야 해당 앱이 호출되어 실행 되어 진다.

<a href="callMyApp://search"> 나의 앱 검색 실행 </a>

위와같이 웹페이지에서 링크를 설정해 두면 해당 앱이 설치되어 있으면 해당 SearchActionActivity가 바로 실행 되어지는 걸 알수 있다.

따라서, 다른 액션의 Activity를 실행하고 싶다면 다른 Activity에 intent-filter만 추가해주면 가능하다.

<activity android:name="TakePhotoActionActivity">
             <intent-filter>  
                <action android:name="android.intent.action.VIEW"/>  
                <category android:name="android.intent.category.DEFAULT"/>  
                <category android:name="android.intent.category.BROWSABLE"/>  
                <data android:scheme="callMyApp" android:host="takePhoto"/>  
            </intent-filter>
</activity>

웹에서 호출 방법은

<a href="callMyApp://takePhoto"> 나의 앱 사진 찍기 실행 </a>


3. 필요에 따라서 앱이 설치 되어 있으면 실행하고 설치 되어 있지 않으면 구글 플레이 마켓으로 이동 하고 싶다고 한다면 intent 전달 방식으로 호출 하면 된다.(Android Only)

기본 형식은 아래와 같다.

Intent://[host명]?파라미터=파리미터값
#Intent;scheme=callMyApp;action=android.intent.action.VIEW;category=android.intent.category.BROWSABLE;package=com.test.myapp;end


간단한 호출 예
<a href="Intent://takePhoto#Intent;scheme=callMyApp;package=com.test.myapp;end">
나의 앱 사진 찍기 실행 </a>




3. 앱에서 파라메터 값 받아서 처리 하기
- 앱에서 호출되어진 Activity 에서 Intent를 통해서 들어온 데이터에서 파라메터 값을 받아서 처리 할수도 있다.

Uri uriData = getIntent().getData();
String photoNumber = uriData.getQueryParameter("photoNumber ");

웹에서 호출
<a href="callMyApp://takePhoto?photoNumber=1"> 나의 앱 1번 사진 보기 </a>


이상으로 웹에서 링크로 안드로이드 앱의 호출을 알아보았습니다.

이것이 되는 것은 Android OS상에서 기본적으로 Intent 호출 방식을 지원하기 때문에 가능하지 않나 생각됩니다.

 



참고 사이트
http://developer.android.com/guide/components/intents-filters.html
http://developer.naver.com/wiki/pages/UrlScheme

 

원본글 URL

 http://gwons.blogspot.kr/2014/11/android.html



출처: https://lkmstar.tistory.com/4 [천지파멸의 이야기]

반응형

댓글()

android 에서 기기에 저장된 파일 이름 변경하기

프로그래밍/Android (Java)|2019. 9. 20. 08:45
반응형

안드로이드 내 파일 이름은 아래 코드로 변경이 가능합니다.


File old_filename = new File(Environment.getExternalStorageDirectory() + "/Download/변경전 파일이름.txt");

File new_filename = new File(Environment.getExternalStorageDirectory() + "/Download/변경후 파일이름.txt");


old_filename.renameTo(new_filename);


결과를 보기 위한 다른 방법은 if 문으로 처리 여부를 확인하는 방법입니다.


if (old_filename.renameTo(new_filename)) {

    Toast.makeText(this, "변경 성공", Toast.LENGTH_SHORT).show();

} else {

    Toast.makeText(this, "변경 실패", Toast.LENGTH_SHORT).show();

}


반응형

댓글()

안드로이드 파일공유 PROVIDER

프로그래밍/Android (Java)|2019. 9. 16. 10:28
반응형
안드로이드에서 파일 공유시 권한 문제로 인해 오류가 발생 된다.

해결 방법


/res/xml/file_provider.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path path="Android/data/${applicationId}/" name="files_root" />
<root-path name="root" path="/" />

</paths> 

또는

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!--Context.getCacheDir() 내부 저장소-->
<cache-path
name="cache"
path="." />
<!--Context.getFilesDir() 내부 저장소-->
<files-path
name="files"
path="." />
<!-- Environment.getExternalStorageDirectory() 외부 저장소-->
<external-path
name="external"
path="." />
<!-- Context.getExternalCacheDir() 외부 저장소-->
<external-cache-path
name="external-cache"
path="." />
<!-- Context.getExternalFilesDir() 외부 저장소-->
<external-files-path
name="external-files"
path="." />
</paths>

 



 <?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="mrsohn.sample"
android:installLocation="auto">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:hardwareAccelerated="true">
<activity
android:name=".SplashActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity
android:name=".MainActivity"
android:screenOrientation="portrait" />


<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.
fileprovider"

android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_path" />
</provider>


</application>

</manifest>



URI얻어오는 방법 

Uri contentUri = FileProvider.getUriForFile(getContext(),

                    getApplicationContext().getPackageName() + ".fileprovider", 파일경로);



content://패키지명.fileprovider/root/data/data/파일경로 형태로 uri가 생성 된다.


 /**

     * 멀티 파일 공유 

     * @param shareFiles

     */

    public void shareMultiFIles(File[] shareFiles) {

        final Intent intent = new Intent();

        intent.setAction(Intent.ACTION_SEND_MULTIPLE);  // 멀티파일 보내기 

//        intent.setPackage("com.google.android.gm");   // 지메일로 보내기 

        // 파일형태에 맞는 type설정

//        intent.setType("plain/text"); // text 형태로 전달

        intent.setType("*/*");        // 모든 공유 형태 전달

        intent.putExtra(Intent.EXTRA_SUBJECT, "공유 제목");  // 제목

        intent.putExtra(Intent.EXTRA_TEXT, "공유 내용");     // 내용

        if (shareFiles != null && shareFiles.length > 0) {

            ArrayList<Uri> uris = new ArrayList<Uri>();

            for (File file : shareFiles) {

                Uri contentUri = FileProvider.getUriForFile(this,

                        getApplicationContext().getPackageName() + ".fileprovider", file); // manifest의  ${applicationId}.fileprovider

                uris.add(contentUri);

                Log.i(TAG, "contentUri="+contentUri.toString());

            }

            intent.putExtra(Intent.EXTRA_STREAM, uris); // 멀티 파일 전송

        }

        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);     // 공유 앱에 권한 주기 

        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);    // 공유 앱에 권한 주기 

        startActivity(Intent.createChooser(intent, "공유 타이틀"));

    } 



    /**

     * 단일 파일 공유 

     * @param shareFile

     */

    public void shareFIle(File shareFile) {

        final Intent intent = new Intent();

        intent.setAction(Intent.ACTION_SEND);           // 단일파일 보내기 

//        intent.setPackage("com.google.android.gm");   // 지메일로 보내기 

        // 파일형태에 맞는 type설정

        MimeTypeMap type = MimeTypeMap.getSingleton();

        intent.setType(type.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(shareFile.getPath())));

//        intent.setType("plain/text"); // text 형태로 전달

//        intent.setType("*/*");        // 모든 공유 형태 전달 

        intent.putExtra(Intent.EXTRA_SUBJECT, "공유 제목");  // 제목

        intent.putExtra(Intent.EXTRA_TEXT, "공유 내용");     // 내용

        Log.i(TAG, "test.file.getpath="+shareFile.getPath());

        if (shareFile != null) {

            Uri contentUri = FileProvider.getUriForFile(this,

                    getApplicationContext().getPackageName() + ".fileprovider", shareFile); // manifest의  ${applicationId}.fileprovider

     

            intent.putExtra(Intent.EXTRA_STREAM, contentUri); // 단일 파일 전송

        }

        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);     // 공유 앱에 권한 주기 

        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);    // 공유 앱에 권한 주기 

        startActivity(Intent.createChooser(intent, "공유 타이틀"));

    } 


[출처] https://mrsohn.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%ED%8C%8C%EC%9D%BC%EA%B3%B5%EC%9C%A0-provider-1


반응형

댓글()

지오코딩 GeoCoding (주소,지명 ↔ 위도,경도 변환) 예제

반응형

안드로이드: 지오코딩 GeoCoding (주소,지명 ↔ 위도,경도 변환)

 

 

지오코딩(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) 권한을 받아옵니다

 

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>

 

 

 

 

[activity_main.xml]

 

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="위도"
android:textAppearance="?android:attr/textAppearanceLarge" />

<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:ems="10"
android:inputType="numberDecimal" />

<EditText
android:id="@+id/editText2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/editText1"
android:layout_alignTop="@+id/textView2"
android:ems="10"
android:inputType="numberDecimal" />

<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/editText2"
android:layout_marginTop="26dp"
android:text="주소"
android:textAppearance="?android:attr/textAppearanceLarge" />

<EditText
android:id="@+id/editText3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/editText2"
android:layout_alignTop="@+id/textView3"
android:ems="10" >

<requestFocus />
</EditText>

<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/editText1"
android:layout_marginTop="22dp"
android:text="경도"
android:textAppearance="?android:attr/textAppearanceLarge" />

<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/editText2"
android:layout_alignBottom="@+id/editText2"
android:layout_alignParentRight="true"
android:text="변환1" />

<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/textView3"
android:layout_alignBottom="@+id/textView3"
android:layout_alignParentRight="true"
android:text="변환2" />

<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="@+id/button2"
android:layout_marginTop="28dp"
android:text="조회한 주소정보 출력"
android:textAppearance="?android:attr/textAppearanceMedium" />

<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/editText2"
android:layout_alignRight="@+id/editText2"
android:text="지도1" />

<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/editText3"
android:layout_alignBottom="@+id/editText3"
android:layout_alignRight="@+id/editText3"
android:text="지도2" />

</RelativeLayout>

 

 

 

 

 

 

 

 

 

[MainActiviy.java]

 

 

 

 

public class MainActivity extends AppCompatActivity {

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

// 지오코딩(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());

Intent intent = new Intent(
Intent.ACTION_VIEW,
Uri.parse("geo:" + d1 + "," + d2));
startActivity(intent);
}
});

b4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 주소입력후 지도2버튼 클릭시 해당 위도경도값의 지도화면으로 이동
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 {
// 해당되는 주소로 인텐트 날리기
Address addr = list.get(0);
double lat = addr.getLatitude();
double lon = addr.getLongitude();

String sss = String.format("geo:%f,%f", lat, lon);

Intent intent = new Intent(
Intent.ACTION_VIEW,
Uri.parse(sss));
startActivity(intent);
}
}
}
});

} // end of onCreate
} // end of class

 

 

 

 

 

[실행화면]

 

 

 

 

 

 

 

 

위 시작화면에서 적절한 주소, 혹은 지명 등을 입력하고 [변환2] 버튼을 누르면

아래와 같이 지오코딩 된 전체정보를 볼수 있습니다.  toString() 결과값

 

 

 

 

 

 

한변 [지도2] 버튼을 누르면, 아래와 같이 지도 앱으로 묵시적인텐트를 날려서

해당 지도앱이 넘겨받은 위도,경도 값으로 지도 표시를 합니다.

 

 

 

 

반면 상단의 위도, 경도 값을 직접 입력하고 [변환1] 을 누르면 이또한 지오코딩이 된 결과값이 나옵니다.

 

 


출처: https://bitsoul.tistory.com/135 [Happy Programmer~]

 

 

반응형

댓글()

폴리라인 (polyline) 그리기

반응형

PolylineOptions polylineOptions = new PolylineOptions();

 

 

String output = out.toString();    // gpx 파일 내용이 output 에 있다고 가정하자.

    String[] split = output.split("\\n");  // 개행 단위로 배열에 넣고
    for(int i=0 ; i<split.length ; i++) {      // 라인 단위로 작업을 시작한다.

        // 정규표현식으로 좌표 값만 가져오기
        if(split[i].contains("lat=") && split[i].contains("lon=")) {

            add_lat = split[i].replaceAll(".*lat=\"", "");
            temp_lat = Double.parseDouble(add_lat.replaceAll("\".*", ""));
            add_lon = split[i].replaceAll(".*lon=\"", "");
            temp_lon = Double.parseDouble(add_lon.replaceAll("\".*", ""));

            polylineOptions.color(Color.RED);  // 폴리라인 옵션에 색상과
            polylineOptions.width(8);                   // 라인 굵기와
            polylineOptions.add(new LatLng(temp_lat, temp_lon)); // 좌표를 반복해서 추가한다.

 

        }

    }

 

 

제거하려는 경우 아래 코드 사용

polyline.remove();

 

 

나쁜 예)

아래와 같이 사용하면 동작은 하나 많은 라인 (테스트시 27,000 라인) 을 가져올때 굉장히 느리며, 앱이 종료되는 현상 발생

mMap.addPolyline(polylineOptions.add(new LatLng(temp_lat, temp_lon)));

 

 

반응형

댓글()

권한 여부 체크하기

반응형

int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CALENDAR);

if (permissionCheck == PackageManager.PERMISSION_DENIED) {

    // 권한 없음
else {
    // 권한 있음
}

 

* 위 파란색 글씨 대신에 다른 권한 대입 가능하다.

 

반응형

댓글()