【问题标题】:How to play GIF in android如何在安卓中播放 GIF
【发布时间】:2013-12-23 08:39:21
【问题描述】:

你好stackoverflow我正在尝试开发一个android应用程序来玩我自己的GIF,这里是代码sn-p

MainActivity.java

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}
}

AnimationView.java

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.util.AttributeSet;
import android.view.View;

public class AnimationView extends View {
private Movie mMovie;
private long mMovieStart;
private static final boolean DECODE_STREAM = true;

private int mDrawLeftPos;
private int mHeight, mWidth;

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 AnimationView(Context context, AttributeSet attrs) {
    super(context, attrs);
    setFocusable(true);
    java.io.InputStream is;
    is = context.getResources().openRawResource(R.drawable.scanning);
    if (DECODE_STREAM) {
        mMovie = Movie.decodeStream(is);
    } else {
        byte[] array = streamToBytes(is);
        mMovie = Movie.decodeByteArray(array, 0, array.length);
    }
}

@Override
protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec )
{   
    int p_top = this.getPaddingTop(), p_bottom = this.getPaddingBottom();

    mWidth = mMovie.width();
    mHeight = mMovie.height();
    // Calculate new desired height
    final int desiredHSpec = MeasureSpec.makeMeasureSpec( mHeight + p_top + p_bottom , MeasureSpec.EXACTLY );

    setMeasuredDimension( widthMeasureSpec, desiredHSpec );
    super.onMeasure( widthMeasureSpec, desiredHSpec );

    // Update the draw left position
    mDrawLeftPos = Math.max( ( this.getWidth() - mWidth ) / 2, 0) ;
}

@Override
public void onDraw(Canvas 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 = 3000;
        }
        int relTime = (int) ((now - mMovieStart) % dur);
        // Log.d("", "real time :: " +relTime);
        mMovie.setTime(relTime);
        mMovie.draw(canvas, mDrawLeftPos, this.getPaddingTop());
        invalidate();
    }
}
}

ma​​in.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:orientation="vertical" >

<com.example.androidgifwork.AnimationView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true" />
</LinearLayout>

Manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidgifwork"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="19" />

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >
    <activity
        android:name="com.example.androidgifwork.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

当我运行上面的代码时 sn -p GIF 根本没有运行,但是当我删除 android:targetSdkVersion="19" GIF 运行时,请帮我解开这个谜。

谢谢

【问题讨论】:

  • 我删除了 android:targetSdkVersion="18" 然后它的工作。有人得到任何解决方案吗?我面临同样的问题。
  • @Akanksha 是的,4.4API 18 及更高版本中存在 Gif 问题,但如果您真的需要,您可以播放 GIF。我不能在这里发布整个源代码以在任何版本的 android 中播放 GIF。请发私信。谢谢。
  • 我怎样才能给你发私信?你能把你的代码发给我吗?

标签: android android-animation


【解决方案1】:

2017 年更新答案

要在 android 中播放 GIF,请使用 Glide 库来加载任何图像或 GIF。

Glide.with(context)
.load(YOUR_GIF)
.into(YOUR_IMAGE_VIEW);

使用 Glide 加载普通图片、来自服务器的图片甚至加载 GIF。还可以看看Picasso android 图片加载库,它类似于 Glide 但截至目前(2017 年 4 月 16 日) Picasso 不支持 GIF 尚未加载到 android 中。


############################################## #######################

老答案

对于所有想要在您的应用中播放 GIF 的人,请在下面找到代码 PlayGifView.java

 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Movie;
 import android.os.Build;
 import android.util.AttributeSet;
 import android.view.View;

 public class PlayGifView extends View{

     private static final int DEFAULT_MOVIEW_DURATION = 1000;

     private int mMovieResourceId;
     private Movie mMovie;

     private long mMovieStart = 0;
     private int mCurrentAnimationTime = 0;

     @SuppressLint("NewApi")
     public PlayGifView(Context context, AttributeSet attrs) {
         super(context, attrs);

        /**
         * Starting from HONEYCOMB have to turn off HardWare acceleration to draw
         * Movie on Canvas.
         */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
    }

     public void setImageResource(int mvId){
         this.mMovieResourceId = mvId;
    mMovie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
    requestLayout();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if(mMovie != null){
        setMeasuredDimension(mMovie.width(), mMovie.height());
    }else{
        setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumHeight());
    }
}

@Override
protected void onDraw(Canvas canvas) {
    if (mMovie != null){
        updateAnimtionTime();
        drawGif(canvas);
        invalidate();
    }else{
        drawGif(canvas);
    }
}

private void updateAnimtionTime() {
    long now = android.os.SystemClock.uptimeMillis();

    if (mMovieStart == 0) {
        mMovieStart = now;
    }
    int dur = mMovie.duration();
    if (dur == 0) {
        dur = DEFAULT_MOVIEW_DURATION;
    }
    mCurrentAnimationTime = (int) ((now - mMovieStart) % dur);
}

private void drawGif(Canvas canvas) {
    mMovie.setTime(mCurrentAnimationTime);
    mMovie.draw(canvas, 0, 0);
    canvas.restore();
}

}

在您的活动类中使用以下代码播放 GIF

PlayGifView pGif = (PlayGifView) findViewById(R.id.viewGif);
pGif.setImageResource(<Your GIF file name Eg: R.drawable.infinity_gif>);

XML 布局

<yourPacckageName.PlayGifView
            android:id="@+id/viewGif"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center" />

【讨论】:

  • 有没有办法从存储中获取 GIF 并在此视图中播放?
  • @sureshcheemalamudi 答案是肯定的,但是您需要覆盖PlayGifView 中的setImageResource(resourceID, resourceType) 方法,它可以接受新参数resourceType,它指定它是GIF 还是图像。但我不推荐它,因为加载图像非常简单且易于实现,除非您有特定要求,否则您可以继续使用我提到的方法。
  • @ChethanShetty 有没有办法减慢 GIF 的动画速度?
  • 谢谢@ChethanShetty 成功了。在我的情况下,我在从 API 获取数据时使用 gif 作为加载器,glide 的问题是,它并不总是从开始加载 gif,它使用最后加载的状态并执行进一步的 gif 动画(因为它维护一个缓存) ,这不符合我的要求。 PlayGifView 在我的情况下工作得很好。谢谢你:)
【解决方案2】:

使用 Glide 将任何 gif 从项目的 raw 文件夹或外部 URL 加载到 ImageView, ImageButtons 或类似的 [Glide targets][2]

Glide.with(getActivity()).load(R.raw.alarm).asGif().into(btnAlert);

【讨论】:

【解决方案3】:

如果您可以使用 WebView,则 GIF 将直接在其上播放。但我不确定,在你的情况下,你是否想把它放在 Webview 中。

【讨论】:

  • 我试过 webview @Sushil 但WebViewKitKat 中无法预测GIF 没有播放。
【解决方案4】:

将此添加到您的依赖项(build.gradle)

 allprojects {
    repositories {
        mavenCentral()
    }
}
dependencies {
    implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.15'
}

并在 xml 中使用它来显示你的 gif

 <pl.droidsonroids.gif.GifTextView
                    android:id="@+id/gifTextView2"
                    android:layout_width="230dp"
                    android:layout_height="200dp"
                    android:layout_weight="1"
                    android:src="@drawable/dev_option_gif"
                    />

更多信息请访问:https://github.com/koral--/android-gif-drawable

【讨论】:

    【解决方案5】:

    Android 提供类 android.graphics.Movie。此类能够解码和播放 InputStreams。所以对于这种方法,我们创建一个类 GifMovieView 并让它继承自 View 一个详细的教程在http://droid-blog.net/2011/10/14/tutorial-how-to-use-animated-gifs-in-android-part-1/给出了一个详细的教程

    【讨论】:

      【解决方案6】:

      源代码 https://drive.google.com/open?id=0BzBKpZ4nzNzUZy1BVlZSbExvYUU

      ** 清单文件中的 android:hardwareAccelerated="false" **

      package com.keshav.gifimageexampleworking;
      
      import android.os.Bundle;
      import android.support.v7.app.AppCompatActivity;
      import android.util.Log;
      
      public class MainActivity extends AppCompatActivity
      {
          private GifImageView gifImageView;
      
          @Override
          protected void onCreate(Bundle savedInstanceState)
          {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              gifImageView = (GifImageView) findViewById(R.id.GifImageView);
      
              gifImageView.setGifImageResource(R.drawable.success1);
      
          }
      
       @Override
       protected void onResume() 
       {
          super.onResume();
      
          //refresh long-time task in background thread
          new Thread(new Runnable() {
              @Override
              public void run() {
                  try {
                      //dummy delay for 2 second
                      Thread.sleep(8000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
      
                  //update ui on UI thread
                  runOnUiThread(new Runnable() {
                      @Override
                      public void run() {
                          gifImageView.setGifImageResource(R.drawable.success);
                      }
                  });
      
              }
          }).start();
         }
      }
      
      
      package com.keshav.gifimageexampleworking;
      
      import android.content.Context;
      import android.graphics.Canvas;
      import android.graphics.Movie;
      import android.net.Uri;
      import android.os.SystemClock;
      import android.util.AttributeSet;
      import android.util.Log;
      import android.view.View;
      
      import java.io.FileNotFoundException;
      import java.io.InputStream;
      
      
      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, 10, 10);
                  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");
              }
          }
      }
      

      【讨论】:

      • 好,还可以参考更新后的答案,使用 Glide 库以最少的代码播放 GIF。
      【解决方案7】:

      对于运行 API 29(Pie) 及更高版本的设备,您可以使用 AnimatedImageDrawable 播放 GIF(s) 和 WebP 动画图像。

      这是一个示例:

      ImageView imgGif = findViewById(R.id.imgGif);
      
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
              try {
                  drawable = ImageDecoder.decodeDrawable(ImageDecoder.createSource(getResources(), R.drawable.giphy));
                  imgGif.setImageDrawable(drawable);
      
                  if (drawable instanceof AnimatedImageDrawable) {
                      ((AnimatedImageDrawable) drawable).start();
                  }
      
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      

      使用此功能可提供更多可用于图像的控制和功能,例如:

      • 检查 gif 是否正在运行
      • 开始和停止播放。
      • 应用滤色器
      • 改变图像形状

        还有很多more

      【讨论】:

        【解决方案8】:

        您还可以使用Coil 库,与 Glide 相比,它使您对 Gif 图像的控制更少。但如果您只想加载一次 GIF 并显示,仍然提供简单的实现。可能,如果您想重复,您需要再次触发可绘制对象,或者只需再次调用加载函数。无论如何,即使再次调用 load 资源也应该在后台缓存(有待调查,不是 100% 确定)。 Everything you need 正在添加依赖:

         implementation "io.coil-kt:coil-gif:1.0.0"
        

        并指定您的解码机制:

        val imageLoader = ImageLoader.Builder(context)
            .componentRegistry {
                if (SDK_INT >= 28) {
                    add(ImageDecoderDecoder())
                } else {
                    add(GifDecoder())
                }
            }
            .build()
        

        一切顺利,直接在您的图像视图中加载图像/GIF:

        app_logo.load("needed_gif_url")
        

        不要忘记将所需的图像加载器传递给需要使用解码器的每个请求,例如 GIF。或者只是将您的自定义 imageLoader 作为每个请求的默认值:

        Coil.setImageLoader(imageLoader)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-01-26
          • 1970-01-01
          • 2012-11-10
          • 2013-05-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多