https://github.com/richardlee-kr/HelltakerM
GIF 재생
이번에는 저번 Floating Widget의 png를 gif으로 바꿔서 움직이게 해보자
사실상 이것만 성공하면 앱의 절반 이상 완성한거다
Glide모듈을 이용해서 gif를 재생해보자
Gradle Scripts - build.gradle에 있는 dependencies에 아래 코드를 추가한다
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
res폴더에 Android Resource Directory를 추가한다
type은 raw로 지정해준다
그리고 여기에 gif 파일을 추가한다
그다음 WidgetService.java에서
ImageView를 추가하고 기존의 tvWidget을 ImageView로 바꾼다
그리고 아래 코드를 통해 Glide모듈을 통해 gif를 재생하는 코드를 추가한다
Glide.with(WidgetService.this).load(R.raw.cerberus).into(imageGIF);
#WidgetService.java
package com.example.floatingwidget;
import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import com.bumptech.glide.Glide;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class WidgetService extends Service {
int LAYOUT_FLAG;
View mFloatingView;
WindowManager windowManager;
ImageView imageClose;
ImageView imageGIF;
float height, width;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O) //if current version is higher than Oreo
{
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}
else
{
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}
//inflate widget layout
mFloatingView = LayoutInflater.from(this).inflate(R.layout.layout_widget,null);
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
LAYOUT_FLAG,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
//initial position
layoutParams.gravity = Gravity.TOP|Gravity.RIGHT;
layoutParams.x = 0;
layoutParams.y = 100;
//layout params for close button
WindowManager.LayoutParams imageParams = new WindowManager.LayoutParams(140,
140,
LAYOUT_FLAG,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
imageParams.gravity = Gravity.BOTTOM|Gravity.CENTER;
imageParams.y = 100;
windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
imageClose = new ImageView(this);
imageClose.setImageResource(R.drawable.close_white);
imageClose.setVisibility(View.INVISIBLE);
windowManager.addView(imageClose, imageParams);
windowManager.addView(mFloatingView, layoutParams);
mFloatingView.setVisibility(View.VISIBLE);
height = windowManager.getDefaultDisplay().getHeight();
width = windowManager.getDefaultDisplay().getWidth();
imageGIF = (ImageView)mFloatingView.findViewById((R.id.gif_image));
Glide.with(WidgetService.this).load(R.raw.cerberus).into(imageGIF);
//show&update current time in textview
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
//tvWidget.setText(new SimpleDateFormat("HH:mm:ss").format(new Date()));
handler.postDelayed(this,1000);
}
}, 10);
//drag movement for widget
imageGIF.setOnTouchListener(new View.OnTouchListener() {
int initialX, initialY;
float initialTouchX, initialTouchY;
long startClickTime;
int MAX_CLICK_DURATION=200;
@Override
public boolean onTouch(View v, MotionEvent motionEvent) {
switch(motionEvent.getAction())
{
case MotionEvent.ACTION_DOWN:
startClickTime = Calendar.getInstance().getTimeInMillis();
imageClose.setVisibility(View.VISIBLE);
initialX = layoutParams.x;
initialY = layoutParams.y;
//touch posision
initialTouchX = motionEvent.getRawX();
initialTouchY = motionEvent.getRawY();
return true;
case MotionEvent.ACTION_UP:
long clickDuration = Calendar.getInstance().getTimeInMillis()-startClickTime;
imageClose.setVisibility(View.GONE);
layoutParams.x = initialX+(int)(initialTouchX-motionEvent.getRawX());
layoutParams.y = initialY+(int)(motionEvent.getRawY()-initialTouchY);
if(clickDuration < MAX_CLICK_DURATION)
{
//Toast.makeText(WidgetService.this, "Time: "+tvWidget.getText().toString(),Toast.LENGTH_SHORT).show();
}
else
{
//remove widget
if(layoutParams.y>(height*0.6))
{
stopSelf();
}
}
return true;
case MotionEvent.ACTION_MOVE:
//calculate x&Y coordinates of view
layoutParams.x = initialX+(int)(initialTouchX-motionEvent.getRawX());
layoutParams.y = initialY+(int)(motionEvent.getRawY()-initialTouchY);
//update layout with new coordinates
windowManager.updateViewLayout(mFloatingView, layoutParams);
if(layoutParams.y>(height*0.6))
{
imageClose.setImageResource(R.drawable.close_white);
}
else
{
imageClose.setImageResource(R.drawable.close_white);
}
return true;
}
return false;
}
});
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
if(mFloatingView!=null)
{
windowManager.removeView(mFloatingView);
}
if(imageClose!=null)
{
windowManager.removeView(imageClose);
}
}
}
실행결과
괜찮아 보이긴 하지만 gif재생이 너무 느리다
glide모듈에서는 속도 조절은 못하는 것 같고...
속도를 조절하려면 원래 윈도우 버전처럼 bitmap으로 나누어서 재생해야할 것 같다
긴 이미지를 가져와서 나눈 다음 재생하는 것은 실패했다
Animation-List
일단 각각 이미지를 가져와서 하는게 낫다고 생각했고 12장의 이미지를 drawable에 추가
그리고 animation-list resource 파일을 추가
list에 item 추가, oneshot="false"는 연속재생하는 거
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<item>android:drawable="@drawable/cerberus01" android:duration="30"</item>
<item>android:drawable="@drawable/cerberus02" android:duration="30"</item>
<item>android:drawable="@drawable/cerberus03" android:duration="30"</item>
<item>android:drawable="@drawable/cerberus04" android:duration="30"</item>
<item>android:drawable="@drawable/cerberus05" android:duration="30"</item>
<item>android:drawable="@drawable/cerberus06" android:duration="30"</item>
<item>android:drawable="@drawable/cerberus07" android:duration="30"</item>
<item>android:drawable="@drawable/cerberus08" android:duration="30"</item>
<item>android:drawable="@drawable/cerberus09" android:duration="30"</item>
<item>android:drawable="@drawable/cerberus10" android:duration="30"</item>
<item>android:drawable="@drawable/cerberus11" android:duration="30"</item>
<item>android:drawable="@drawable/cerberus12" android:duration="30"</item>
</animation-list>
그리고 WidgetService.java에 관련 코드를 넣어준다
AnimationDrawable drawable = (AnimationDrawable) img.getResouce();
drawable.start();
마지막으로 ImageView의 src를 설정해준다]
<ImageView
android:id="@+id/gif_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/cerberus"/>
.xml에서 duration값을 변경하여 속도를 조절할 수는 있으나 코드상에서 조절하는 것은 불가능했다
허허....
Animation.addFrame()
찾아보니 animation.addFrame()은 인자로 duration을 받는다
기존에 drawable에 만들었던 .xml은 지우고 values에 새로운 .xml파일을 만든다
name이 cerberus인 array 추가
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="cerberus">
<item>@drawable/cerberus01</item>
<item>@drawable/cerberus02</item>
<item>@drawable/cerberus03</item>
<item>@drawable/cerberus04</item>
<item>@drawable/cerberus05</item>
<item>@drawable/cerberus06</item>
<item>@drawable/cerberus07</item>
<item>@drawable/cerberus08</item>
<item>@drawable/cerberus09</item>
<item>@drawable/cerberus10</item>
<item>@drawable/cerberus11</item>
<item>@drawable/cerberus12</item>
</array>
</resources>
그리고 TypedArray를 통해 반복문을 이용해서 addFrame을 해준다
duration 변수를 선언하고
#밑에 사용자 정의 함수 부분에 추가
private void selectCerberus() {
TypedArray typedArray = getResources().obtainTypedArray(R.array.cerberus);
for (int i =0; i< 12; i++)
{
ani_image.addFrame(typedArray.getDrawable(i),duration);
}
}
그리고 애니메이션 재생
ani_image = new AnimationDrawable();
selectCerberus();
img.setBackgroundDrawable(ani_image);
ani_image.start();
아래처럼 setBackgroundDrawable에 취소선이 그어지긴 하는데 잘 실행된다
에뮬레이터를 실행할 때마다 애가 맛이 가는 것같은데...
다음에는 duration값을 MainActivity에서 받아와서 속도를 조절해보자
'프로젝트 > 헬테이커 스티커 M' 카테고리의 다른 글
헬테이커 스티커 M#4 - 캐릭터 선택 (0) | 2021.06.11 |
---|---|
헬테이커 스티커 M#3 - 프레임 속도 선택 (0) | 2021.06.04 |
헬테이커 스티커 M#1 - Floating Widget 다시 만들기 (1) | 2021.05.14 |
헬티이커 스티커 M#0 - code review (0) | 2021.05.07 |
(구)헬테이커 스티커 모바일 만들기- floating widget (3) | 2020.08.11 |