728x90
반응형

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=30, 우: duration=10

에뮬레이터를 실행할 때마다 애가 맛이 가는 것같은데...

 

다음에는 duration값을 MainActivity에서 받아와서 속도를 조절해보자