애니메이션 GIF 표시


261

응용 프로그램에 애니메이션 GIF 이미지를 표시하고 싶습니다. 안드로이드가 애니메이션 GIF를 기본적으로 지원하지 않는 어려운 방법을 발견했습니다.

그러나 AnimationDrawable을 사용하여 애니메이션을 표시 할 수 있습니다 .

개발> 안내서> 이미지 및 그래픽> 드로어 블 개요

이 예제는 응용 프로그램 리소스에 프레임으로 저장된 애니메이션을 사용하지만 필요한 것은 애니메이션 GIF를 직접 표시하는 것입니다.

내 계획은 애니메이션 GIF를 프레임으로 나누고 각 프레임을 AnimationDrawable에 드로어 블로 추가하는 것입니다.

누구나 애니메이션 GIF에서 프레임을 추출하고 각 프레임을 Drawable 로 변환하는 방법을 알고 있습니까?


2
android 내에서 또는 외부 도구를 사용하여 gif에서 프레임을 추출합니까?
Osmund

확실히 버그 입니다. 자세한 내용 은 IssueTracker 를 참조하십시오.
fbtb

애니메이션 GIF를 표시 할 수있는 앱을 검색하여 여기에 온 모든 사람들을 위해 : quickPic
rubo77


fresco를 사용하여 GIF 표시 github.com/facebook/fresco 이것이 간단한 해결책이라고 생각합니다.
kaitian521

답변:


191

Android는 실제로 android.graphics.Movie 클래스를 사용하여 애니메이션 GIF를 디코딩하고 표시 할 수 있습니다.

너무 많이 문서화되어 있지는 않지만 SDK Reference에 있습니다. 또한 BitmapDecode 예제의 ApiDemos 샘플에서 일부 애니메이션 플래그가 사용됩니다.


9
이것이 얼마나 안정적인가요? 내 앱, Ice Cream Sandwich 장치에서 전혀 작동하지 않고 2.3 에뮬레이터에서는 작동하지만 GIF ​​프레임 중 일부는 버그가 있습니다 (잘못된 색상). 컴퓨터에서는 물론 잘 작동합니다. 무엇을 제공합니까?
Benoit Duffez

12
@Bicou HC 후 장치에서는 setLayerType(LAYER_TYPE_SOFTWARE)View에 있어야 합니다. 그러나 여전히 일부 GIF 및 일부 장치에서만 작동합니다.
Michał K

9
@ MichałK 감사합니다! Paint p = new Paint(); p.setAntiAlias(true); setLayerType(LAYER_TYPE_SOFTWARE, p);일했다!
클로이

1
@ lubosz : LAYER_TYPE_SOFTWARE는 설정하기에 충분해야합니다.
Pointer Null

2
영화 수업은 의도적으로 문서화되어 있지 않습니다. 약하고 지원되지 않습니다. 적절한 Gif 애니메이션이 필요한 경우 직접 구현하는 것이 좋습니다. NDK를 사용하여 내 앱에서 해냈습니다.
포인터 Null

60

최신 정보:

글라이드 사용 :

dependencies {
  implementation 'com.github.bumptech.glide:glide:4.0.0'
}

용법:

Glide.with(context).load(GIF_URI).into(new GlideDrawableImageViewTarget(IMAGE_VIEW));

문서를 참조하십시오


1
지금은 괜찮아 보입니다. 분명히 전체 라이브러리를 포함 할 수는 없으므로 호출 예제로 충분합니다.
gaborous

@gaborous 분명히 플래그를 지정할 때 코드가 포함되지 않았습니다.
Jan

1
NDK를 이미 사용하고 있다면이 라이브러리를 사용하지 않는 것이 좋습니다. 이 lib를 gradle에 추가 한 후 Unity 모듈의 작동이 중지되었습니다.
RominaV

이것은 내가 찾은 최고의 라이브러리입니다. 내가 붙어있는 한 가지는 gif 이미지를 확대하기 위해 꼬집음을 구현하는 것입니다. 아무도 아는가?
독사

28

또한 (main / assets / htmls / name.gif) [이 html로 크기를 조정하십시오.]

<html style="margin: 0;">
<body style="margin: 0;">
<img src="name.gif" style="width: 100%; height: 100%" />
</body>
</html>

Xml에서 다음과 같이 선언하십시오 (main / res / layout / name.xml) : [예를 들어 크기를 정의합니다]

<WebView
android:layout_width="70dp"
android:layout_height="70dp"
android:id="@+id/webView"
android:layout_gravity="center_horizontal" />

활동에서 다음 코드를 onCreate 안에 넣으십시오.

web = (WebView) findViewById(R.id.webView); 
web.setBackgroundColor(Color.TRANSPARENT); //for gif without background
web.loadUrl("file:///android_asset/htmls/name.html");

동적으로로드하려면 데이터와 함께 웹보기를로드해야합니다.

// or "[path]/name.gif" (e.g: file:///android_asset/name.gif for resources in asset folder), and in loadDataWithBaseURL(), you don't need to set base URL, on the other hand, it's similar to loadData() method.
String gifName = "name.gif";
String yourData = "<html style=\"margin: 0;\">\n" +
        "    <body style=\"margin: 0;\">\n" +
        "    <img src=" + gifName + " style=\"width: 100%; height: 100%\" />\n" +
        "    </body>\n" +
        "    </html>";
// Important to add this attribute to webView to get resource from outside.
webView.getSettings().setAllowFileAccess(true);

// Notice: should use loadDataWithBaseURL. BaseUrl could be the base url such as the path to asset folder, or SDCard or any other path, where your images or the other media resides related to your html
webView.loadDataWithBaseURL("file:///android_asset/", yourData, "text/html", "utf-8", null);
// Or if you want to load image from SD card or where else, here is the idea.
String base = Environment.getExternalStorageDirectory().getAbsolutePath().toString();
webView.loadDataWithBaseURL(base + '/', yourData, "text/html", "utf-8", null);

제안 : 자세한 정보 확인을 위해 정적 이미지가있는 gif를로드하는 것이 좋습니다 https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

그게 다야, 나는 당신이 도움이되기를 바랍니다.


2
sdcard에서 GIF를로드하려면?
Jaydev

당신이 sdcard에서로드하려는 경우 : 이미지의 URI에 대한 "file : ///android_asset/htmls/name.html"을 교체
Alex Zaraos

이 방법을 사용하여 gif 파일의 이름을 동적으로 변경하려면 어떻게해야합니까? 내 응용 프로그램에 표시해야 할 모든 GIF와 함께 HTML 파일을 만들고 싶지 않습니다
scrayne

GIF 웹뷰?!? 성능, 메모리 소비 및 배터리에 대해 생각 했습니까?
Duna

@Duna 5 년 전, 현재 예를 들어 글라이드를 사용할 수 있습니다.
Alex Zaraos

22

휴대 전화에 저장하기 전에 GIF 애니메이션을 프레임 으로 분할하여 문제를 해결 했으므로 Android에서 처리하지 않아도됩니다.

그런 다음 모든 프레임을 휴대 전화로 다운로드하고 Drawable을 만든 다음 AnimationDrawable 을 만듭니다. 제 질문의 예와 매우 비슷합니다.


2
애니메이션을 처리하는 문서화 된 방법입니다.
RichieHH

16

여기에서 훌륭하고 간단한 작업 예제를 통해 매우 쉬운 방법을 찾았습니다.

애니메이션 위젯 표시

그것이 작동하기 전에 코드에서해야 할 몇 가지 혼란이 있습니다.

다음에

    @Override
    public void onCreate(Bundle savedInstanceState){    
        super.onCreate(savedInstanceStated);   
        setContentView(new MYGIFView());
    }    
}

그냥 교체

setContentView(new MYGIFView());

setContentView(new MYGIFView(this));

그리고 안으로

public GIFView(Context context) {
    super(context);

나만의 gif 애니메이션 파일 제공

    is = context.getResources().openRawResource(R.drawable.earth);
    movie = Movie.decodeStream(is);
}

첫 번째 라인 교체

public MYGIFView(Context context) {

수업 이름에 따라 ...

이 작은 변화가 끝나면 나처럼 작동해야합니다 ...

이 도움을 바랍니다


2
어떤 안드로이드 버전에서 이것을 시도 했습니까? 안드로이드 버전 2.2와 2.3에서 시도했지만 Movie 객체 null을 반환합니다. 무엇이 잘못 될 수 있는지 아십니까?
Ashwini Shahapurkar

16
이 답변을 임의로 정리하십시오.
taxeeta

2
대답의 문제점은 무엇입니까? 방금 링크를 제공하고 작동시키기 위해 필요한 수정 사항을 제공했습니다
Apperside

10

Android에서 애니메이션 GIF를 표시하는 방법 :

  • 영화 수업. 위에서 언급했듯이 상당히 버그가 있습니다.
  • WebView. 사용이 매우 간단하고 일반적으로 작동합니다. 그러나 때로는 잘못 작동하기 시작하고 항상 가지고 있지 않은 일부 모호한 장치에 있습니다. 또한 메모리에 영향을 미치기 때문에 모든 종류의 목록보기에서 여러 인스턴스를 사용할 수 없습니다. 여전히 주요 접근 방식으로 고려할 수 있습니다.
  • GIF를 비트 맵으로 디코딩하고 Drawable 또는 ImageView로 표시하는 사용자 지정 코드입니다. 두 개의 라이브러리를 언급하겠습니다.

https://github.com/koral--/android-gif-drawable- 디코더는 C로 구현되므로 매우 효율적입니다.

https://code.google.com/p/giffiledecoder- 디코더는 Java로 구현되므로 작업하기가 더 쉽습니다. 대용량 파일에서도 여전히 효율적입니다.

또한 GifDecoder 클래스를 기반으로하는 많은 라이브러리를 찾을 수 있습니다. Java 기반 디코더이기도하지만 전체 파일을 메모리에로드하여 작동하므로 작은 파일에만 적용 할 수 있습니다.


10

안드로이드에서 애니메이션 GIF를 사용하는 것은 정말 힘들었습니다. 나는 두 가지 일만했다.

  1. WebView
  2. 이온

WebView는 정상적으로 작동하지만 실제로는 뷰로드 속도가 느려지고 앱이 1 초 동안 응답하지 않습니다. 나는 그것을 좋아하지 않았다. 그래서 다른 접근법을 시도했습니다 (작동하지 않았습니다).

  1. ImageViewEx 는 더 이상 사용되지 않습니다!
  2. 피카소 는 애니메이션 GIF를로드하지 않았다
  3. android-gif-drawable 은 훌륭하게 보이지만 프로젝트에서 유선 NDK 문제가 발생했습니다. 로컬 NDK 라이브러리가 작동을 멈추고 고칠 수 없었습니다.

나는 몇 가지를주고 받았다 Ion. 마지막으로, 나는 작동하고 있으며, 정말 빠릅니다 :-)

Ion.with(imgView)
  .error(R.drawable.default_image)
  .animateGif(AnimateGifMode.ANIMATE)
  .load("file:///android_asset/animated.gif");

android-gif-drawable과 동일한 NDK 관련 문제가 있습니다.
RominaV

안녕하세요 @RominaV, gif를로드 할 때 진행률 표시 줄을 사용 했습니까? gif를로드 할 때 진행률을 표시해야하기 때문입니다.
patel135

9

글라이드 4.6

1. gif를로드하려면

GlideApp.with(context)
            .load(R.raw.gif) // or url
            .into(imageview);

2. 파일 객체를 얻으려면

GlideApp.with(context)
                .asGif()
                .load(R.raw.gif) //or url
                .into(new SimpleTarget<GifDrawable>() {
                    @Override
                    public void onResourceReady(@NonNull GifDrawable resource, @Nullable Transition<? super GifDrawable> transition) {

                        resource.start();
                      //resource.setLoopCount(1);
                        imageView.setImageDrawable(resource);
                    }
                });

8

Glide

Google에서 권장하는 Android 용 이미지 로더 라이브러리.

  • 글라이드는 피카소와 매우 유사하지만 피카소보다 훨씬 빠릅니다.
  • 글라이드는 피카소보다 적은 메모리를 사용합니다.

글라이드가 가지고 있지만 피카소는하지 않는 것

간단한 ImageView에 GIF 애니메이션을로드하는 기능은 Glide의 가장 흥미로운 기능 일 수 있습니다. 그리고 네, 피카소로는 그렇게 할 수 없습니다. 몇 가지 중요한 링크여기에 이미지 설명을 입력하십시오

  1. https://github.com/bumptech/glide
  2. http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/ko

Google은 어디에서 Glid를 추천하나요?
Derzu

1
개발자 Android 팀이 샘플 앱에서 글라이드를 사용한 위치를 확인하십시오. developer.android.com/samples/XYZTouristAttractions/Application/…
Shoeb Siddique

1
'글라이드는 피카소와 매우 유사하지만 피카소보다 훨씬 빠릅니다.'와 '글라이드는 피카소보다 적은 메모리를 사용합니다.' 죄송합니다.이 아이디어에 만족하지 않습니다. medium.com/@multidots/glide-vs-picasso-930eed42b81d 링크를 선호하십시오 . Btw, 빌드를 3.0.1 (느린 인터넷 연결)로 업그레이드 할 수 없기 때문에 지금 Glide 4.0을 테스트 할 수 없습니다. 그러나 gif를 표시하는 데 Glide 3.5.2를 테스트했지만 큰 img (깜박임)에서 예상 한대로 작동하지만 완벽하게 작동하지는 않습니다.이 또한 일반적인 문제입니다. CMIW 부탁드립니다.
Nguyen Tan Dat

7

사용 ImageViewEx ,을 사용하는 등 쉽게로 GIF를 사용하게 도서관 ImageView.


이것은 더 이상 사용되지 않습니다
Martin Marconcini

이 라이브러리 코드를 살펴 봤는데 2 년 이상 좋았습니다.
NightSkyCode

1
예, 저자가 더 이상 사용하지 않기로 결정했다고 지적하면 비교적 괜찮습니다. 피카소는 이미지 다운로더이며 많은 다운로드 / 캐시보다 더 이상 애니메이션 GIF를 표시 할 때 도움이되지 않기 때문에 이상하게도 피카소와 같은 것을 사용해야한다고 지적합니다. 거기 도구.
Martin Marconcini

6

이것을 시도하십시오, 진행률 표시 줄에 다음 코드 표시 gif 파일

loading_activity.xml (레이아웃 폴더)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff" >

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:indeterminate="true"
        android:indeterminateDrawable="@drawable/custom_loading"
        android:visibility="gone" />

</RelativeLayout>

custom_loading.xml (드로어 블 폴더에 있음)

여기에 black_gif.gif를 넣을 수 있습니다 (드로어 블 폴더에), 여기에 자신의 GIF를 넣을 수 있습니다

<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/black_gif"
    android:pivotX="50%"
    android:pivotY="50%" />

LoadingActivity.java (res 폴더에 있음)

public class LoadingActivity extends Activity {

    ProgressBar bar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_loading);
        bar = (ProgressBar) findViewById(R.id.progressBar);
        bar.setVisibility(View.VISIBLE);

    }

}

나는 당신이 GIF를 회전 참조하십시오. 왜?
AlikElzin-kilaka

Drawable 폴더에 GIF를 어떻게 넣을 수 있습니까?
Apurva


5

내가 제안 된 솔루션을 성공 있었 이 문서 내에서 ,라는 클래스 GifMovieView렌더링, View다음 표시 또는 특정에 추가 할 수있는가 ViewGroup. 지정된 기사의 2 부와 3 부에 제시된 다른 방법을 확인하십시오.

이 방법의 유일한 단점은 영화의 앤티 앨리어싱이 그다지 좋지 않다는 것입니다 ( "shady"Android Movie클래스 사용의 부작용이어야 함 ). 그런 다음 애니메이션 GIF 내에서 배경을 단색으로 설정하는 것이 좋습니다.


4

BitmapDecode 예제에 대한 몇 가지 생각 ... 기본적으로 android.graphics 의 고대이지만 특징이없는 Movie 클래스를 사용합니다 . 최신 API 버전에서는 여기에 설명 된대로 하드웨어 가속을 해제해야합니다 . 그렇지 않으면 나를 위해 segfaulting했다.

<activity
            android:hardwareAccelerated="false"
            android:name="foo.GifActivity"
            android:label="The state of computer animation 2014">
</activity>

다음은 GIF 부분만으로 단축 된 BitmapDecode 예제입니다. 당신은 당신의 자신의 위젯 (보기)를 만들고 스스로 그려야합니다. ImageView만큼 강력하지는 않습니다.

import android.app.Activity;
import android.content.Context;
import android.graphics.*;
import android.os.*;
import android.view.View;

public class GifActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new GifView(this));
    }

    static class GifView extends View {
        Movie movie;

        GifView(Context context) {
            super(context);
            movie = Movie.decodeStream(
                    context.getResources().openRawResource(
                            R.drawable.some_gif));
        }
        @Override
        protected void onDraw(Canvas canvas) {   
            if (movie != null) {
                movie.setTime(
                    (int) SystemClock.uptimeMillis() % movie.duration());
                movie.draw(canvas, 0, 0);
                invalidate();
            }
        }
    }
}

ImageView를 사용하는 다른 두 가지 방법, WebView를 사용하는 다른 방법은 이 훌륭한 자습서 에서 찾을 수 있습니다 . ImageView 메소드는 Google 코드 의 Apache 라이센스 android-gifview 를 사용합니다 .


1
@ luboz 당신은 안드로이드 성능에 어떤 방법이 좋은지 알려주십시오 ... 스플래시 화면 로딩 바에 애니메이션 GIF를 사용하고 싶습니다. 어떤 방법이 더 좋은지 제안 해 주시겠습니까? 또한 이미지보기 방법을 사용하여 스케일 유형 속성을 사용할 수 있다는 것을 알고 싶습니다.
스왑

4

@PointerNull은 좋은 해결책을 주었지만 완벽하지는 않습니다. 파일 크기가 큰 일부 장치에서는 작동하지 않으며 ICS 이전 버전에서는 델타 프레임이있는 버그가있는 Gif 애니메이션이 표시됩니다. 이 버그없이 해결책을 찾았습니다. koral의 android-gif-drawable : 네이티브 디코딩이 가능한 라이브러리입니다 .


2

기본 브라우저는 gif 파일을 지원하므로 WebView에 넣으면 올바르게 표시 할 수 있어야합니다. (Froyo +, 내가 실수하지 않으면)


사실이 아닙니다. 모든 브라우저가 GIF를 지원하는 것은 아닙니다.
RichieHH

4
잘만되면 우리는 모든 브라우저가 필요하지 않습니다 ... 주식 브라우저는 안드로이드 2.2 이후 그것을 지원하므로, 날 downvote하지 마십시오. WebView는 반드시 GIF를 표시합니다!
keybee

2

애니메이션 GIF를 Android 앱에로드하는 두 가지 옵션이 있습니다

1) 글라이드 를 사용하여 gif를에로드합니다 ImageView.

    String urlGif = "https://cdn.dribbble.com/users/263558/screenshots/1337078/dvsd.gif";
    //add Glide implementation into the build.gradle file.
    ImageView imageView = (ImageView)findViewById(R.id.imageView);
    Uri uri = Uri.parse(urlGif);
    Glide.with(getApplicationContext()).load(uri).into(imageView);

2) html을 사용하여 GIF를 WebView

.gif 파일의 주소로 HTML을 작성하십시오.

<html style="margin: 0;">
<body style="margin: 0;">
<img src="https://..../myimage.gif" style="width: 100%; height: 100%" />
</body>
</html>

이 파일을 자산 디렉토리에 저장하십시오.

여기에 이미지 설명을 입력하십시오

이 HTML을 응용 프로그램의 WebView에로드하십시오.

    WebView webView =  (WebView)findViewById(R.id.webView);
    webView = (WebView) findViewById(R.id.webView);
    webView.loadUrl("file:///android_asset/html/webpage_gif.html");

다음 은이 두 옵션완전한 예입니다 .

여기에 이미지 설명을 입력하십시오


2

Android API (Android Pie) 28 및 + 만

AnimatedImageDrawable을 다음 과 같이 사용하십시오.

// ImageView from layout
val ima : ImageView = findViewById(R.id.img_gif)
// create AnimatedDrawable 
val decodedAnimation = ImageDecoder.decodeDrawable(
        // create ImageDecoder.Source object
        ImageDecoder.createSource(resources, R.drawable.tenor))
// set the drawble as image source of ImageView
ima.setImageDrawable(decodedAnimation)
// play the animation
(decodedAnimation as? AnimatedImageDrawable)?.start()

XML 코드, ImageView 추가

<ImageView
    android:id="@+id/img_gif"
    android:background="@drawable/ic_launcher_background" <!--Default background-->
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    android:layout_width="200dp"
    android:layout_height="200dp" />

AnimatedImageDrawable Drawable의 자식이며 ImageDecoder.decodeDrawable

ImageDecoder.decodeDrawableImageDecoder.Source의해 생성 된 인스턴스가 더 필요 했습니다 ImageDecoder.createSource.

ImageDecoder.createSource소스를 이름, ByteBuffer, File, resourceId, URI, ContentResolver로만 가져 와서 소스 오브젝트를 작성하고이를 사용 AnimatedImageDrawable하여 Drawable(다형성 호출)

static ImageDecoder.Source  createSource(AssetManager assets, String fileName)
static ImageDecoder.Source  createSource(ByteBuffer buffer)
static ImageDecoder.Source  createSource(File file)
static ImageDecoder.Source  createSource(Resources res, int resId)
static ImageDecoder.Source  createSource(ContentResolver cr, Uri uri)

참고 : ImageDecoder # decodeBitmap을Bitmap 사용하여 만들 수도 있습니다 .

산출:

AnimatedDrawable은 크기 조정, 프레임 및 색상 조작도 지원합니다


1

gif 파일을 처리하는 더 좋은 라이브러리는 다음과 같습니다.

그것을 사용하고 나는 성공 하고이 라이브러리는 GIF 전용입니다; 그러나 피카소와 글라이드범용 이미지 프레임 워크 인 곳; 그래서이 라이브러리의 개발자는 완전히 gif 파일에 집중했다고 생각합니다.



1

Movie 클래스가 더 이상 사용되지 않는다고 추가하고 싶었습니다 .

이 클래스는 API 레벨 P에서 더 이상 사용되지 않습니다.

이것을 사용하는 것이 좋습니다

AnimatedImageDrawable

GIF와 같은 애니메이션 이미지를 그리는 데 사용할 수 있습니다.


1

src 폴더에“Utils”라는 패키지를 생성하고“GifImageView”라는 클래스를 생성

public class GifImageView extends View {
    private InputStream mInputStream;
    private Movie mMovie;
    private int mWidth, mHeight;
    private long mStart;
    private Context mContext;
    public GifImageView(Context context) {
        super(context);
        this.mContext = context;
    }
    public GifImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public GifImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        if (attrs.getAttributeName(1).equals("background")) {
            int id = Integer.parseInt(attrs.getAttributeValue(1).substring(1));
            setGifImageResource(id);
        }
    }
    private void init() {
        setFocusable(true);
        mMovie = Movie.decodeStream(mInputStream);
        mWidth = mMovie.width();
        mHeight = mMovie.height();
        requestLayout();
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(mWidth, mHeight);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        long now = SystemClock.uptimeMillis();
        if (mStart == 0) {
            mStart = now;
        }
        if (mMovie != null) {
            int duration = mMovie.duration();
            if (duration == 0) {
                duration = 1000;
            }
            int relTime = (int) ((now - mStart) % duration);
            mMovie.setTime(relTime);
            mMovie.draw(canvas, 0, 0);
            invalidate();
        }
    }
    public void setGifImageResource(int id) {
        mInputStream = mContext.getResources().openRawResource(id);
        init();
    }
    public void setGifImageUri(Uri uri) {
        try {
            mInputStream = mContext.getContentResolver().openInputStream(uri);
            init();
        } catch (FileNotFoundException e) {
            Log.e("GIfImageView", "File not found");
        }
    }
}

이제 MainActivity 파일에서 GifImageView를 정의하십시오 : src / activity / MainActivity.class

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        GifImageView gifImageView = (GifImageView) findViewById(R.id.GifImageView);
        gifImageView.setGifImageResource(R.drawable.smartphone_drib);
    }
}

이제 UI 파트 파일 : res / layout / activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:gravity="center"
    android:background="#111E39"
    tools:context=".Activity.MainActivity">
    <com.android.animatedgif.Utils.GifImageView
        android:id="@+id/GifImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

</RelativeLayout>

Resourece 코드 : 안드로이드 예제


이미지 크기 조정 방법, pls
The Dead Guy

0

우선 모든 Android 브라우저는 애니메이션 GIF를 지원해야합니다. 그렇지 않으면 버그입니다! 이슈 트래커를 살펴보십시오.

이러한 애니메이션 GIF를 브라우저 외부에 표시하는 경우 다른 스토리 일 수 있습니다. 요청한 작업을 수행하려면 애니메이션 GIF의 디코딩을 지원하는 외부 라이브러리가 필요합니다.

첫 번째 호출 포트는 Java2D 또는 JAI (Java Advanced Imaging) API를 살펴 보는 것이지만 Android Dalvik이 앱에서 해당 라이브러리를 지원할 경우 매우 놀랍습니다.


일부 장치는 웹 브라우저에서도 애니메이션 GIF를 표시하지 않습니다. 예를 들어, 안드로이드 2.3.6의 갤럭시 미니는 그것들을 보여주지 않는다는 것을 알고 있습니다.
안드로이드 개발자

0

@Leonti가 말한 것과 비슷하지만 조금 더 깊이가 있습니다.

동일한 문제를 해결하기 위해 김프를 열고, 하나를 제외한 모든 레이어를 숨기고, 자신의 이미지로 내 보낸 다음, 해당 레이어를 숨기고 다음 레이어 등을 숨 깁니다. . 그런 다음 AnimationDrawable XML 파일에서 프레임으로 사용할 수 있습니다.


1
시간이 없으면 gifsicle 을 사용하여 프레임을 추출 할 수 있습니다 . 또한 python 또는 bash는 XML 파일을 생성 할 때 매우 편리합니다.
lubosz

0

프레임에서 gif를 분할하고 표준 안드로이드 애니메이션을 사용 하여이 문제를 해결했습니다.


0

앱에서 gif를 표시하기 위해 내가 한 일. 사람들이 자유롭게 속성을 사용할 수 있도록 ImageView를 확장했습니다. URL 또는 자산 디렉토리에서 gif를 표시 할 수 있습니다. 라이브러리는 클래스를 확장하여 클래스에서 상속하고 gif를 초기화하는 다른 메소드를 지원하도록 확장 할 수 있도록합니다.

https://github.com/Gavras/GIFView

github 페이지에는 약간의 가이드가 있습니다.

Android Arsenal에도 게시되었습니다.

https://android-arsenal.com/details/1/4947

사용 예 :

XML에서 :

<com.whygraphics.gifview.gif.GIFView xmlns:gif_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/main_activity_gif_vie"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:scaleType="center"
        gif_view:gif_src="url:http://pop.h-cdn.co/assets/16/33/480x264/gallery-1471381857-gif-season-2.gif" />

활동에서 :

    GIFView mGifView = (GIFView) findViewById(R.id.main_activity_gif_vie);

    mGifView.setOnSettingGifListener(new GIFView.OnSettingGifListener() {
                @Override
                public void onSuccess(GIFView view, Exception e) {
                    Toast.makeText(MainActivity.this, "onSuccess()", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onFailure(GIFView view, Exception e) {

        }
});

프로그래밍 방식으로 gif 설정 :

mGifView.setGifResource("asset:gif1");

0

가장 쉬운 방법-아래 코드를 고려할 수 있습니다

Imageview setImageResource를 활용할 수 있습니다. 아래 코드를 참조하십시오.

아래 코드는 gif의 다중 분할 이미지가있는 경우 gif와 같은 이미지를 표시하는 데 사용할 수 있습니다. 온라인 도구에서 GIF를 개별 png로 나누고 아래 순서와 같이 이미지를 드로어 블에 넣으십시오.

image_1.png, image_2.png 등

핸들러가 이미지를 동적으로 변경하도록합니다.

int imagePosition = 1;
    Handler handler = new Handler();
        Runnable runnable = new Runnable() {
            public void run() {
                updateImage();
            }
        };




    public void updateImage() {

                appInstance.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        int resId = getResources().getIdentifier("image_" + imagePosition, "drawable", appInstance.getPackageName());
                        gifImageViewDummy.setImageResource(resId);
                        imagePosition++;
    //Consider you have 30 image for the anim
                        if (imagePosition == 30) {
//this make animation play only once
                            handler.removeCallbacks(runnable);

                        } else {
    //You can define your own time based on the animation
                            handler.postDelayed(runnable, 50);
                        }

//to make animation to continue use below code and remove above if else
// if (imagePosition == 30)
//imagePosition = 1;
// handler.postDelayed(runnable, 50);
// 
                    }
                });
              }

0

URL에서 앱 레이아웃으로 애니메이션 GIF를 직접 표시하는 쉬운 방법은 WebView 클래스를 사용하는 것입니다.

1 단계 : 레이아웃 XML

<WebView
android:id="@+id/webView"
android:layout_width="50dp"
android:layout_height="50dp"
/>

2 단계 : 활동

WebView wb;
wb = (WebView) findViewById(R.id.webView);
wb.loadUrl("https://.......);

3 단계 : 당신의 Manifest.XML 메이크 인터넷 권한에서

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

4 단계 : GIF 배경을 투명하게 만들고 GIF를 레이아웃에 맞추려면

wb.setBackgroundColor(Color.TRANSPARENT);
wb.getSettings().setLoadWithOverviewMode(true);
wb.getSettings().setUseWideViewPort(true);


해결 방법하지만 상당한 개발자 덕분에 비 네이티브는 메모리에 미치는 영향, CPU 사용량 및 배터리 수명과 같은 시사점 인해 렌더링하고 싶지 않을 수도 있습니다
RUX


-8
public class Test extends GraphicsActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new SampleView(this));
  }

  private static class SampleView extends View {
    private Bitmap mBitmap;
    private Bitmap mBitmap2;
    private Bitmap mBitmap3;
    private Bitmap mBitmap4;
    private Drawable mDrawable;

    private Movie mMovie;
    private long mMovieStart;

    // Set to false to use decodeByteArray
    private static final boolean DECODE_STREAM = true;

    private static byte[] streamToBytes(InputStream is) {
      ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
      byte[] buffer = new byte[1024];
      int len;
      try {
        while ((len = is.read(buffer)) >= 0) {
          os.write(buffer, 0, len);
        }
      } catch (java.io.IOException e) {
      }
      return os.toByteArray();
    }

    public SampleView(Context context) {
      super(context);
      setFocusable(true);

      java.io.InputStream is;
      is = context.getResources().openRawResource(R.drawable.icon);

      BitmapFactory.Options opts = new BitmapFactory.Options();
      Bitmap bm;

      opts.inJustDecodeBounds = true;
      bm = BitmapFactory.decodeStream(is, null, opts);

      // now opts.outWidth and opts.outHeight are the dimension of the
      // bitmap, even though bm is null

      opts.inJustDecodeBounds = false; // this will request the bm
      opts.inSampleSize = 4; // scaled down by 4
      bm = BitmapFactory.decodeStream(is, null, opts);

      mBitmap = bm;

      // decode an image with transparency
      is = context.getResources().openRawResource(R.drawable.icon);
      mBitmap2 = BitmapFactory.decodeStream(is);

      // create a deep copy of it using getPixels() into different configs
      int w = mBitmap2.getWidth();
      int h = mBitmap2.getHeight();
      int[] pixels = new int[w * h];
      mBitmap2.getPixels(pixels, 0, w, 0, 0, w, h);
      mBitmap3 = Bitmap.createBitmap(pixels, 0, w, w, h,
          Bitmap.Config.ARGB_8888);
      mBitmap4 = Bitmap.createBitmap(pixels, 0, w, w, h,
          Bitmap.Config.ARGB_4444);

      mDrawable = context.getResources().getDrawable(R.drawable.icon);
      mDrawable.setBounds(150, 20, 300, 100);

      is = context.getResources().openRawResource(R.drawable.animated_gif);

      if (DECODE_STREAM) {
        mMovie = Movie.decodeStream(is);
      } else {
        byte[] array = streamToBytes(is);
        mMovie = Movie.decodeByteArray(array, 0, array.length);
      }
    }

    @Override
    protected void onDraw(Canvas canvas) {
      canvas.drawColor(0xFFCCCCCC);

      Paint p = new Paint();
      p.setAntiAlias(true);

      canvas.drawBitmap(mBitmap, 10, 10, null);
      canvas.drawBitmap(mBitmap2, 10, 170, null);
      canvas.drawBitmap(mBitmap3, 110, 170, null);
      canvas.drawBitmap(mBitmap4, 210, 170, null);

      mDrawable.draw(canvas);

      long now = android.os.SystemClock.uptimeMillis();
      if (mMovieStart == 0) { // first time
        mMovieStart = now;
      }
      if (mMovie != null) {
        int dur = mMovie.duration();
        if (dur == 0) {
          dur = 1000;
        }
        int relTime = (int) ((now - mMovieStart) % dur);
        mMovie.setTime(relTime);
        mMovie.draw(canvas, getWidth() - mMovie.width(), getHeight()
            - mMovie.height());
        invalidate();
      }
    }
  }
}

class GraphicsActivity extends Activity {
  // set to true to test Picture
  private static final boolean TEST_PICTURE = false;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
  }

  @Override
  public void setContentView(View view) {
    if (TEST_PICTURE) {
      ViewGroup vg = new PictureLayout(this);
      vg.addView(view);
      view = vg;
    }

    super.setContentView(view);
  }
}

class PictureLayout extends ViewGroup {
  private final Picture mPicture = new Picture();

  public PictureLayout(Context context) {
    super(context);
  }

  public PictureLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  @Override
  public void addView(View child) {
    if (getChildCount() > 1) {
      throw new IllegalStateException(
          "PictureLayout can host only one direct child");
    }

    super.addView(child);
  }

  @Override
  public void addView(View child, int index) {
    if (getChildCount() > 1) {
      throw new IllegalStateException(
          "PictureLayout can host only one direct child");
    }

    super.addView(child, index);
  }

  @Override
  public void addView(View child, LayoutParams params) {
    if (getChildCount() > 1) {
      throw new IllegalStateException(
          "PictureLayout can host only one direct child");
    }

    super.addView(child, params);
  }

  @Override
  public void addView(View child, int index, LayoutParams params) {
    if (getChildCount() > 1) {
      throw new IllegalStateException(
          "PictureLayout can host only one direct child");
    }

    super.addView(child, index, params);
  }

  @Override
  protected LayoutParams generateDefaultLayoutParams() {
    return new LayoutParams(LayoutParams.MATCH_PARENT,
        LayoutParams.MATCH_PARENT);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    final int count = getChildCount();

    int maxHeight = 0;
    int maxWidth = 0;

    for (int i = 0; i < count; i++) {
      final View child = getChildAt(i);
      if (child.getVisibility() != GONE) {
        measureChild(child, widthMeasureSpec, heightMeasureSpec);
      }
    }

    maxWidth += getPaddingLeft() + getPaddingRight();
    maxHeight += getPaddingTop() + getPaddingBottom();

    Drawable drawable = getBackground();
    if (drawable != null) {
      maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
      maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
    }

    setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec),
        resolveSize(maxHeight, heightMeasureSpec));
  }

  private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx,
      float sy) {
    canvas.save();
    canvas.translate(x, y);
    canvas.clipRect(0, 0, w, h);
    canvas.scale(0.5f, 0.5f);
    canvas.scale(sx, sy, w, h);
    canvas.drawPicture(mPicture);
    canvas.restore();
  }

  @Override
  protected void dispatchDraw(Canvas canvas) {
    super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight()));
    mPicture.endRecording();

    int x = getWidth() / 2;
    int y = getHeight() / 2;

    if (false) {
      canvas.drawPicture(mPicture);
    } else {
      drawPict(canvas, 0, 0, x, y, 1, 1);
      drawPict(canvas, x, 0, x, y, -1, 1);
      drawPict(canvas, 0, y, x, y, 1, -1);
      drawPict(canvas, x, y, x, y, -1, -1);
    }
  }

  @Override
  public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
    location[0] = getLeft();
    location[1] = getTop();
    dirty.set(0, 0, getWidth(), getHeight());
    return getParent();
  }

  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    final int count = super.getChildCount();

    for (int i = 0; i < count; i++) {
      final View child = getChildAt(i);
      if (child.getVisibility() != GONE) {
        final int childLeft = getPaddingLeft();
        final int childTop = getPaddingTop();
        child.layout(childLeft, childTop,
            childLeft + child.getMeasuredWidth(),
            childTop + child.getMeasuredHeight());

      }
    }
  }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.