16 Aug 2019
|
Android
기존에 Java 버전의 Runtime Permission을 포스팅 했었지만
이번에는 Kotlin 버전으로 포스팅합니다.
private const val PERMISSION_REQUEST_CODE = 1231
class MainActivity : AppCompatActivity() {
private val permissions = arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (!checkPermissions(permissions)) {
requestPermissions(permissions, PERMISSION_REQUEST_CODE)
}
}
private fun checkPermissions(permissions: Array<String>): Boolean {
for (permission in permissions) {
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
return false
}
}
return true
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
PERMISSION_REQUEST_CODE -> {
if ((grantResults.isNotEmpty()) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
} else {
Toast.makeText(applicationContext, "Permission is not granted.", Toast.LENGTH_SHORT).show()
}
}
}
}
}
11 Aug 2019
|
Android
gradle
에서 변수를 사용하는 방법입니다.
예를 들어 특정 라이브러리의 버전을 변수로 지정할 수 있습니다.
build.gradle (Project)
buildscript {
ext.kotlin_version = '1.3.41'
ext.snowlib_version = 'latest.integration'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
build.gradle (Module)
그리고 아래 예제와 같은 방법으로 위에서 선언한 snowlib_version
이라는 변수를 사용할 수 있습니다.
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':common_library')
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation group: 'snowdeer.message.utils', name: 'snowdeer-message-util', version: "$snowlib_version", changing: true
implementation group: 'snowdeer.actiontool.library', name: 'snowdeer-actiontool-library', version: "$snowlib_version", changing: true
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
05 Aug 2019
|
Android
먼저 View
를 상속받는 캔버스(Canvas)를 가진 클래스를 하나 구현합니다. 그리고 setPercentage
메소드를 만들어줍니다.
클래스 외부에서 애니메이션을 동작시킬 때 필요한 progress
관련 메소드입니다.
class PathView(context: Context, attrs: AttributeSet) : View(context, attrs) {
companion object {
private const val CORNER_ROUND = 40F
}
private val wayPointList = ArrayList<PointF>()
private val paint = Paint()
private var progress = 0F
private var pathLength = 0F
init {
paint.apply {
color = context.getColor(R.color.path_color)
style = Paint.Style.STROKE
isAntiAlias = true
strokeWidth = 8.0F
strokeCap = Paint.Cap.ROUND
strokeJoin = Paint.Join.ROUND
}
initDummyData()
}
private fun initDummyData() {
wayPointList.add(PointF(190F, 1715F))
wayPointList.add(PointF(270F, 1715F))
wayPointList.add(PointF(270F, 650F))
wayPointList.add(PointF(460F, 650F))
wayPointList.add(PointF(460F, 500F))
}
fun setPath(pointList: ArrayList<Point>) {
wayPointList.clear()
for (p in pointList) {
val x = MapCoordinateConverter.getCanvasXFromWorldX(p.x).toFloat()
val y = MapCoordinateConverter.getCanvasXFromWorldX(p.y).toFloat()
wayPointList.add(PointF(x, y))
}
invalidate()
}
fun setPercentage(percentage: Float) {
if (percentage < 0.0f || percentage > 1.0f) {
throw IllegalArgumentException("setPercentage not between 0.0f and 1.0f")
}
progress = percentage
invalidate()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
drawPath(canvas)
}
private fun drawPath(canvas: Canvas?) {
val p = createPath()
val measure = PathMeasure(p, false)
pathLength = measure.length
val total = pathLength - pathLength * progress
val pathEffect = DashPathEffect(floatArrayOf(pathLength, pathLength), total)
val cornerPathEffect = CornerPathEffect(CORNER_ROUND)
paint.pathEffect = ComposePathEffect(cornerPathEffect, pathEffect)
canvas?.drawPath(p, paint)
}
private fun createPath(): Path {
val p = Path()
if(wayPointList.size > 0) {
p.moveTo(wayPointList[0].x, wayPointList[0].y)
for (pf in wayPointList) {
p.lineTo(pf.x, pf.y)
}
}
return p
}
}
위에서 만든 클래스를 외부에서 사용할 때는 다음과 같이 작성하면 됩니다.
class MapView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) {
private val pathView = PathView(context, attrs)
init {
val layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT)
addView(pathView, layoutParams)
}
fun start() {
playPathAnimation(pathView)
}
fun setPath(pointList: ArrayList<Point>) {
pathView.setPath(pointList)
}
private fun playPathAnimation(target: View) {
val anim = ObjectAnimator.ofFloat(target, "percentage", 0.0f, 1.0f)
anim.duration = 3000
anim.interpolator = LinearInterpolator()
anim.start()
}
}
03 Aug 2019
|
Android
TextView
에 Text가 렌더링되기 전에 미리 width를 얻는 코드입니다.
Text의 width는 TextView에서 출력되는 폰트의 종류와 크기 등에 영향을 받기 때문에, TextView의 현재 Paint()
정보를 가져와서 계산을 해줍니다.
textView.setText(texxt);
int width = (int)textView.getPaint().measureText(text);
24 Jul 2019
|
Android
package com.snowdeer.animation.sample.fragment
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.transition.*
import com.snowdeer.animation.sample.R
import kotlinx.android.synthetic.main.fragment_scene_change.view.*
import kotlinx.android.synthetic.main.scene1.view.*
class SceneChangeFragment :Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_scene_change, container, false)
val scene1 = Scene(view.scene_root!!, view.container)
val scene2 = Scene.getSceneForLayout(view.scene_root, R.layout.scene2, activity!!)
val scene3 = Scene.getSceneForLayout(view.scene_root, R.layout.scene3, activity!!)
view.scene_1_button.setOnClickListener {
TransitionManager.go(scene1)
}
view.scene_2_button.setOnClickListener {
val set = TransitionSet()
val slide = Slide(Gravity.LEFT)
slide.addTarget(R.id.image2)
set.addTransition(slide)
set.addTransition(ChangeBounds())
set.ordering = TransitionSet.ORDERING_TOGETHER
set.duration = 350
TransitionManager.go(scene2, set)
}
view.scene_3_button.setOnClickListener {
TransitionManager.go(scene3)
}
return view
}
}