[Swift5] 버튼 보이게 / 보이지 않게 하기

(Android와 비교)


iOS 앱 개발을 하다보면 버튼을 보이게 하거나 보이지 않게 해야하는 경우가 있습니다.

이런 경우 코드로는 어떻게 표현을 해야하는지를 알아보겠습니다.

 

우선 안드로이드에서 사용하는 버튼을 보이거나 보이지 않게하는 방법입니다. (setVisibility함수 사용)

 

Android에서 사용하는 방법(Java)

private Button btn_test

//init
btn_test = findViewById(R.id.btn_test);

//버튼을 보이지 않게
btn_test.setVisibility(View.INVISIBLE);

//버튼을 보이게
btn_test.setVisibility(View.VISIBLE);

 

iOS에서는 @IBOutlet으로 Storyboard에서 간단하게 드래그로 변수 선언을 해주시고, layer의 isHidden을 이용해 컨트롤합니다.

 

iOS에서 사용하는 방법입니다.(Swift5)

@IBOutlet weak var btn_test: UIButton!

//버튼 보이지 않게
btn_test.layer.isHidden = true

//버튼 보이게
btn_test.layer.isHidden = false

 

단, 위 코드는 UIBarButtonItem 컴포넌트에서는 먹히지 않습니다. (layer가 선언이 되는 컴포넌트는 전부 가능 - Button, View 등)

 

컴포넌트가 UIBarButtonItem인 경우(Swift5)

@IBOutlet weak var navigation_btn_test: UIBarButtonItem!

//버튼 보이지 않게
navigation_btn_test.isEnabled = false
navigation_btn_test.tintColor = UIColor.clear

//버튼 보이게
navigation_btn_test.isEnabled = true
navigation_btn_test.tintColor = UIColor.black

 

UIBarButtonItem 컴포넌트의 경우 아무래도 isHidden을 사용할 수 없는 모양입니다.

(객체 내에서 Hidden을 시킬 수 있는 함수나 멤버가 없는 모양)

따라서 위의 소스는

1. 버튼을 사용하지 못하게 막음.

2. 색상을 없애버려 없는 버튼처럼 만들어 줌.

두가지를 이용했다고 보시면 됩니다.

 

단, 이는 제가 아직 부족한 부분이 많아서 다른 좋은 방법이 있을 수 있으므로, 좋은 방법이 있다면 업데이트 해두도록 하겠습니다.

(소스의 표현방식은 각양각색이니까요!)

 

 

테스트 장비 : 맥미니(2020)

 

버전정보 (v1.0)

 - v1.0 2020.07.01 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.com


[Java] Activity 화면 방향 회전시 제어하기 (Sensor옵션)


 

지난 시간에 Activity 화면의 방향을 제어하는 방법에 대해서 알아보았습니다. (링크)

 

여기서는 sensor옵션 관련(sensor, fullsensor, sensorLandscape, sensorPortrait) 옵션을 주고 회전시에 화면을 제어하는 방법에 대해서 알아보도록 하겠습니다.

 

Manifest에서 화면의 방향을 제어할 옵션을 준 Activity Class에서 onCreate 함수에

displayManager를 선언해 Listner를 등록해주면 됩니다.

아래는 DisplayManager를 선언하고 Listener를 등록해주는 소스

DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
displayManager.registerDisplayListener(displayListener, null);

 

위 소스를 입력하시면 displayListener가 없다고 에러가 날겁니다.

아래는 우리에게 필요한 Listener(displayListener)를 생성합니다.

DisplayManager.DisplayListener displayListener = new DisplayManager.DisplayListener() {
  @Override
  public void onDisplayAdded(int displayId) {
  	//디스플레이가 시스템에서 추가될 때
  }

  @Override
  public void onDisplayRemoved(int displayId) {
  	//디스플레이가 시스템에서 삭제될 때
  }

  @Override
  public void onDisplayChanged(int displayId) {
  	//디스플레이가 변경될때마다
  }
};

위 선언된 Listener에서 내부 Override된 onDisplayChanged 함수를 이용하시면 Activity가 회전될 때마다 캐치하여 원하는 소스를 실행할 수 있습니다.

 

참조

https://developer.android.com/reference/android/hardware/display/DisplayManager.DisplayListener

 

버전정보 (v1.0)

 - v1.0 2020.06.27 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.com

 


[Kotlin, Java] Activity 화면 방향 설정


안드로이드의 Activity 설정 시 Orientation을 지정하는 방법을 설명합니다.

 

AndroidManifest.xml에 Orientation 설정을 바꿀 Activity에 대해 특성 한가지만 추가(수정)해주면 됩니다.

 - android:screenOrientation = "옵션값"

  -> screenOrientation 특성은 Activity의 방향을 설정할 수 있습니다.

  -> 단, Activity가 다중창모드(멀티태스킹, 화면 분할)로 실행이 된다면 이 특성은 무시됩니다.

  -> 옵션값 (자주 사용할만한 옵션값에는 Bold 처리)

 

unspecified behind landscape portrait
reverseLandscape reversePortrait sensorLandscape sensorPortrait
userLandscape userPortrait sensor fullSensor
nosensor user fullUser locked

 

-> 자주 사용하는 옵션값만 설명을 하자면,

 landscape는 Activity를 가로방향으로 고정합니다.

 portrait는 Activity를 세로방향으로 고정합니다.

 sensorLandscape는 Activity를 가로방향으로 고정을 하고, sensor의 값에 따라 반전이 될 수 있습니다.

 sensorPortrait는 Activity를 세로방향으로 고정을 하고, sensor의 값에 따라 반전이 될 수 있습니다.

 sensor의 경우 사용자가 들고있는 방향에 따라 Activity의 방향이 결정됩니다.

  -- sensor 사용시 4방향에 대한 설정이 이루어지지 않는다면 fullSensor를 사용해 보세요.

 

 - AndroidManifest.xml에서 설정하는법.

방향 설정을 원하는 Activity 설정 안에 android:screenOrientation 특성을 주어 원하는 옵션값을 부여합니다.

(원하는 옵션값은 상단에서 선택합니다.)

* Android Studio 3.6 이상에서는 사용자가 screenOrientation을 지정하면 에러를 낼 수 있습니다.

 - 이는 unspecified(default -> 시스템이 방향을 선택)와 fullSensor 이외의 옵션값을 사용할 때 일어나는 문제로, tools:ignore="LockedOrientationActivity" 특성과 옵션값을 주어 에러를 무시할 수 있습니다.(오류 무시)

 

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

 

참조

https://developer.android.com/guide/topics/manifest/activity-element?hl=ko

 

<액티비티>  |  Android 개발자  |  Android Developers

Declares an activity (an Activity subclass) that implements part of the application's visual user interface. All activities must be represented by {@code } elements in the manifest file. Any that are not declared there will not be seen by the system…

developer.android.com

 

버전정보 (v1.0)

 - v1.0 2020.06.26 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.com





[Kotlin, JAVA]

밀리세컨드 단위 시간 구하기


간혹 파일명을 만든다던가하는 특수한 경우마다 중복이 일어나지 않기 위해 밀리세컨드 단위의 시간을 구해야하는 경우가 있습니다.

(키값이 중복되지 않는다는 점에선 가장 편한 방법일지도 모르겠지요. 주요 예로는 파일의 저장(영상, 사진) 등)

 

 - Kotlin 현재 시간 구하기

System.currentTimeMillis()

val testTime = "${System.currentTimeMillis()}"

 

 - JAVA 현재 시간 구하기

System.currentTimeMillis();

String testTime = String.valueOf(System.currentTimeMillis());

 

return type는 long형입니다.

 

 *** Reference : https://developer.android.com/reference/java/lang/System#currentTimeMillis()

 

System  |  Android 개발자  |  Android Developers

System public final class System extends Object java.lang.Object    ↳ java.lang.System The System class contains several useful class fields and methods. It cannot be instantiated. Among the facilities provided by the System class are standard input, stand

developer.android.com

 *** 소스에 문제가 있을 시 댓글달아주시면 최신화하도록 하겠습니다. 감사합니다

 


[Kotlin]Handler 이용하여 메인 UI 건드리기

(메인 쓰레드 제어하기)


Timer등을 설정해서 로직을 돌리다보면 이벤트에 따라 UI가 변경되어야하는 경우가 있습니다.

 

쉽게말해 UI를 건드리기 위해 서브쓰레드에서 메인쓰레드를 제어한다는건데, 여기서는 Timer를 실행했을때를 예시로 들겠습니다.

 

 - Timer를 통해 i를 증가시키기

private fun timerTest() {
  var i = 0
  myTimer = timer(period = 1000) {
    i++
    handlerTest(i)
  }
}​

  > 위처럼 타이머를 설정하여 1초(period=1000)마다 i를 증가시킨다는 예시를 들겠습니다.

 

 - Handler를 생성하여 UI를 바꿔주기

private fun handlerTest(msg:Int) {
    val handler : Handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(inputMessage: Message) {
            timer_text.setText(msg)
        }
    }
    handler.obtainMessage().sendToTarget()
}

 

  > timerTest 함수에서는 i를 증가시켜 handlerTest 함수에 해당 i값을 매개변수로 넘겨주어 메인쓰레드(UI)를 제어하는 형식입니다.

  > 위 함수에서는 timer_text(TextView)에 1씩 증가시켜 UI단에서 보이게 해줍니다.

 

 *** Reference : https://developer.android.com/reference/android/os/Handler?hl=en

 

Handler  |  Android 개발자  |  Android Developers

Handler public class Handler extends Object java.lang.Object    ↳ android.os.Handler A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and

developer.android.com

 *** 소스에 문제가 있을 시 댓글달아주시면 최신화하도록 하겠습니다. 감사합니다.

 


[Kotlin]Toast 사용하기


간혹 유저에게 간단한 메세지를 전달해주기위해 Toast를 사용하는 경우가 있습니다.

이런 경우를 위해 Kotlin에서의 Toast 사용법을 알아보겠습니다.

 

- 기본 형태

Toast.makeText(context, text, duration).show()

 > context(Context)는 현재 Activity의 context를 전달해주시면 되며,

 > text(String)는 Toast에 띄우고 싶은 String형식의 text를,

 > duration(Int)은 Toast를 얼마나 긴 혹은 짧은 시간동안 보이게하고 싶은지를 의미합니다.

 > duration의 경우 Toast.LENGTH_SHORT 및 Toast.LENGTH_LONG을 사용할 수 있으며 각각 0과 1로 대치됩니다. (즉, 0 혹은 1로 넣어도 동작)

 > SHORT는 4000ms(4초), LONG은 7000ms(7초) 입니다.

 

 > *makeText 후 show를 사용하지 않으면 Toast는 보이지 않습니다.

 

 - 예시

Toast.makeText(this, "토스트 테스트_짧게", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "토스트 테스트_길게", Toast.LENGTH_LONG).show()

위는 비교적 간단한 예시이며, duration부분의 SHORT와 LONG의 차이로 Toast를 짧은 시간 혹은 긴 시간동안 보이게 해주는 예시입니다.

 

 - 간단하게 함수를 이용하여 Text만 받아 사용하기

private fun shortToast(text:String) {
	Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
}

private fun longToast(text:String) {
	Toast.makeText(this, text, Toast.LENGTH_LONG).show()
}

 - 사용법 :

  shortToast("안녕! Karzin!")

  longToast("안녕! Karzin!")

 

 *** Reference : https://developer.android.com/reference/android/widget/Toast

 

Toast  |  Android 개발자  |  Android Developers

Toast public class Toast extends Object java.lang.Object    ↳ android.widget.Toast A toast is a view containing a quick little message for the user. The toast class helps you create and show those. When the view is shown to the user, appears as a floating

developer.android.com

 *** 소스에 문제가 있을 시 댓글달아주시면 최신화하도록 하겠습니다. 감사합니다.


[Kotlin]Activity 전체화면 처리


예전에는 뭔가 AndroidManifest.xml에서 android:theme의 설정을 조금 만져주면 되었던걸로 기억하는데(개발한지 오래되서 맞는지는..) 최근버전에서는 많이 달라진것같네요.

 

전체화면모드가 생겨서 lean back, Immersive, sticky immersive라는 3가지 옵션으로 앱의 전체화면을 컨트롤하는 모양입니다.

 

private fun fullScreen(fullScreenOption : Int) {
  window.decorView.systemUiVisibility = (
    fullScreenOption
    or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
    or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
    or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
    or View.SYSTEM_UI_FLAG_FULLSCREEN )
}​

 - fullScreenOption은 전체화면의 옵션을 설정해주기위한겁니다.

 - Immersive, sticky immersive

 - Immersive 옵션 : View.SYSTEM_UI_FLAG_IMMERSIVE

 - sticky immersive 옵션 : View.SYSTEM_UI_IMMERSIVE_STICKY

 - 위 두 옵션은 상태표시줄이나, 탐색메뉴를 없애 전체화면으로 만들어주며, 필요시 아래나 위에서 스와이프 동작을 하면 상태표시줄과 탐색메뉴가 동시에 보이게 됩니다.

 - 다만 sticky immersive옵션을 주면 상태표시줄이나, 탐색메뉴가 불투명하게 보이며, 스와이프 후 일정시간이 지나면 다시 전체화면으로 돌아가지만, Immersive옵션의 경우 스와이프 후 상태표시줄과 탐색메뉴가 불투명하지 않고, 일정시간이 지나도 계속 존재함을 확인하실 수 있습니다. (촬영 등에 탐색이벤트를 사용할일이 적은 Activity에 적합해보입니다.)

 - 만일 lean back 옵션을 주고 싶다면, fullScreenOption 매개변수를 지워주시면 됩니다. (lean back 옵션의 경우 Activity를 터치하면 상태표시줄과 탐색메뉴가 나오게됩니다. - 유저가 동영상을 보다가 어떠한 탐색 이벤트 등을 발생하고 싶을때 적합한듯 보입니다.), 아래 예시 참조

private fun fullScreen() {
  window.decorView.systemUiVisibility = (
    or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
    or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
    or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
    or View.SYSTEM_UI_FLAG_FULLSCREEN )
}

 

 - 위 함수는 onWindowFocusChanged 함수안에서 실행해주면 됩니다. (아래 예제 참조)

override fun onWindowFocusChanged(hasFocus : Boolean) {
  super.onWindowFocusChanged(hasFocus)
  if(hasFocus) fullScreen(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
}​

 - onWindowFocusChanged함수는 Activity의 선택(Focus)여부를 확인하는 함수입니다. (override하여 사용하시면 됩니다.) 

 - Activity가 포커스 되면 fullScreen이 되는 형식입니다.

 - lean back 옵션의 경우 매개변수를 넘겨주지않으면 됩니다.

  >> fullScreen()

 

 *** Reference : https://developer.android.com/training/system-ui/immersive?hl=ko

 

전체 화면 모드 사용 설정  |  Android 개발자  |  Android Developers

동영상, 게임, 이미지 갤러리, 책, 프레젠테이션 슬라이드 같은 콘텐츠를 이용하기에 최적의 환경은 전체 화면입니다. 이 페이지에서는 전체 화면에서 사용자를 콘텐츠에 더욱 몰입하게 하는 방법과 사용자가 앱을 실수로 종료하지 않도록 하는 방법을 설명합니다. 앱에 화면 공간을 최대한 활용하겠다는 단순한 이유로 전체 화면 모드를 사용 설정하려고 할 수 있습니다. 하지만 사용자가 알림 확인이나 즉흥적인 검색 등을 위해 얼마나 자주 앱을 시작하고 종료하는지 고려해야

developer.android.com

 *** 소스에 문제가 있을 시 댓글달아주시면 최신화하도록 하겠습니다. 감사합니다.

 

 


[Kotlin]안드로이드 권한 요청


 

 

권한요청은 JAVA 버전도 만들었었지만 이번에 개발하는 Kotlin(이하 코틀린)에서 사용할 권한 요청을 정리해 보았습니다. (JAVA는 추후에 다시)

 

1. JAVA와 동일하게 AndroidManifest.xml에서 권한을 요청할 permission을 지정해줍니다.

 예 ) <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

      //저장소 쓰기에 대한 권한 요청

2. PermissionCheck Class (아래 소스코드 참고)

class PermissionCheck(val permissionActivity: Activity, val requirePermissions: Array<String>) {

    private val permissionRequestCode = 100

    //권한 체크용
    public fun permissionCheck() {
        var failRequestPermissionList = ArrayList<String>()

        for(permission in  requirePermissions) {
            if(ContextCompat.checkSelfPermission(permissionActivity.applicationContext, permission) != PackageManager.PERMISSION_GRANTED) {
                failRequestPermissionList.add(permission)
            }
        }

        if(failRequestPermissionList.isNotEmpty()) {
            val array = arrayOfNulls<String>(failRequestPermissionList.size)
            ActivityCompat.requestPermissions(permissionActivity, failRequestPermissionList.toArray(array), permissionRequestCode)
        }
    }
}

 - 첫번째 매개변수는 Activity를 넘겨받으며, 두번째 매개변수는 Array 즉, 권한요청할 permission의 배열을 받아옵니다.

 - permissionCheck 함수를 돌려주면 permission 배열내에서 권한승인이 되지않은 권한을 모드 failRequestPermissionList 로 담아줍니다. 담아준 결과는 Empty 즉, 빈값이 아니라면 권한을 요청하게됩니다.

 

3. 실행할 위치에 권한요청할 permission의 Array를 생성해주고(아래 requestPermissions), PermissionCheck 클래스의 permissionCheck 함수를 실행해줍니다.

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)

  var requestPermissions = arrayOf(
  Manifest.permission.WRITE_EXTERNAL_STORAGE
  )

  val permissionCheck = PermissionCheck(this, requestPermissions)
  permissionCheck.permissionCheck()
}

 

** 만일 permissionCheck 함수를 실행하지 않고 바로 실행하고 싶다면 init 활용 (아래 참조)

class PermissionCheck(val permissionActivity: Activity, val requirePermissions: Array<String>) {

    private val permissionRequestCode = 100

    //권한 체크용
    init {
        var failRequestPermissionList = ArrayList<String>()

        for(permission in  requirePermissions) {
            if(ContextCompat.checkSelfPermission(permissionActivity.applicationContext, permission) != PackageManager.PERMISSION_GRANTED) {
                failRequestPermissionList.add(permission)
            }
        }

        if(failRequestPermissionList.isNotEmpty()) {
            val array = arrayOfNulls<String>(failRequestPermissionList.size)
            ActivityCompat.requestPermissions(permissionActivity, failRequestPermissionList.toArray(array), permissionRequestCode)
        }
    }
}

 -> 사용시에는 아래처럼 PermissionCheck 클래스에 매개변수만 담아주면 권한체크가 실행됩니다.

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)

  var requestPermissions = arrayOf(
  Manifest.permission.WRITE_EXTERNAL_STORAGE
  )

  PermissionCheck(this, requestPermissions)
}

 

*** Reference : https://developer.android.com/training/permissions/requesting?hl=ko

*** 소스에 문제가 있을 시 댓글 달아주시면 최신화하도록하겠습니다.

+ Recent posts