Hiển thị GIF hoạt hình


261

Tôi muốn hiển thị hình ảnh GIF hoạt hình trong ứng dụng của tôi. Như tôi đã tìm ra một cách khó khăn, Android không hỗ trợ GIF động.

Tuy nhiên, nó có thể hiển thị hình ảnh động bằng AnimationDrawable :

Phát triển> Hướng dẫn> Hình ảnh & Đồ họa> Tổng quan về Drawables

Ví dụ sử dụng hoạt hình được lưu dưới dạng khung trong tài nguyên ứng dụng nhưng điều tôi cần là hiển thị gif hoạt hình trực tiếp.

Kế hoạch của tôi là phá vỡ GIF hoạt hình thành các khung và thêm từng khung có thể vẽ vào AnimationDrawable.

Có ai biết cách trích xuất các khung hình từ GIF hoạt hình và chuyển đổi từng khung hình thành Drawable không?


3
Bạn có nghĩa là trong Android, hoặc trích xuất khung hình từ gif bằng một công cụ bên ngoài?
Osmund

Đây chắc chắn là một lỗi, xem IssueTracker để biết thêm thông tin.
fbtb

Chỉ dành cho tất cả những người đến đây bằng cách tìm kiếm một ứng dụng có thể hiển thị GIF động: quickPic
rubo77


Sử dụng fresco để hiển thị GIF github.com/facebook/fresco Tôi nghĩ rằng đây là một giải pháp đơn giản.
kaiti521

Câu trả lời:


191

Android thực sự có thể giải mã và hiển thị GIF động, sử dụng lớp android.graphics.Movie.

Đây không phải là quá nhiều tài liệu, nhưng là trong Tài liệu tham khảo SDK . Hơn nữa, nó được sử dụng trong Các mẫu trong ApiDemos trong ví dụ BitmapDecode với một số cờ hoạt hình.


9
Làm thế nào ổn định này là? Tôi đã triển khai nó trong ứng dụng của mình, trên thiết bị Ice Cream Sandwich của tôi, nó hoàn toàn không hoạt động, trên trình giả lập 2.3 nó đang hoạt động nhưng một số khung GIF bị lỗi (sai màu). Trên máy tính, nó hoạt động tốt. Đưa cái gì?
Benoit Duffez

12
@Bicou Trên các thiết bị sau HC, bạn nên setLayerType(LAYER_TYPE_SOFTWARE)xem. Nhưng nó vẫn chỉ hoạt động cho một số gifs và cho một số thiết bị.
Michał K

9
@ MichałK Cảm ơn bạn! Paint p = new Paint(); p.setAntiAlias(true); setLayerType(LAYER_TYPE_SOFTWARE, p);đã làm việc!
Chloe

1
@lubosz: LAYER_TYPE_SOFTware nên đủ để đặt.
Con trỏ Null

2
Lớp phim không có giấy tờ về mục đích - nó yếu và không được hỗ trợ. Nếu bạn cần hình ảnh động Gif thích hợp, bạn nên tự mình thực hiện nó. Tôi đã làm nó cho ứng dụng của tôi bằng cách sử dụng NDK.
Con trỏ Null

60

CẬP NHẬT:

Sử dụng lướt

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

sử dụng:

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

xem tài liệu


1
Bây giờ có vẻ ổn với tôi, rõ ràng câu trả lời không thể bao gồm toàn bộ thư viện, vì vậy ví dụ cuộc gọi có vẻ đủ.
gabious

@gabious Rõ ràng mã không được bao gồm tại thời điểm gắn cờ.
ngày

1
Tôi không khuyên bạn nên sử dụng thư viện này nếu bạn đã sử dụng NDK. Sau khi thêm lib này vào lớp, mô-đun Unity ngừng hoạt động.
RominaV

Đây là thư viện tốt nhất mà tôi đã tìm thấy. Một điều mà tôi đang mắc kẹt là triển khai pinch để phóng to hình ảnh gif. Có ai biết không?
viper

28

cũng đặt (chính / tài sản / htmls / name.gif) [với html này điều chỉnh kích thước]

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

khai báo trong Xml của bạn, ví dụ như thế này (main / res / layout / name.xml): [ví dụ: bạn xác định kích thước]

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

trong Hoạt động của bạn đặt mã tiếp theo vào bên trong onCreate

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

nếu bạn muốn tải động, bạn phải tải webview bằng dữ liệu:

// 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);

đề xuất: tải gif tốt hơn với hình ảnh tĩnh để kiểm tra thêm thông tin https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

Đó là nó, tôi hy vọng bạn giúp đỡ.


2
Nếu tôi muốn tải GIF từ sdcard?
Jaydev

nếu bạn muốn tải từ sdcard: thay thế "tệp: ///android_asset/htmls/name.html" cho uri của hình ảnh của bạn
Alex Zaraos

Sử dụng phương pháp này, làm thế nào tôi có thể thay đổi tên của tệp gif một cách linh hoạt? Tôi không muốn tạo một tệp html để đi với mọi gif tôi cần hiển thị trong ứng dụng của mình
scrayne

Webview cho một GIF?!? Bạn đã nghĩ về hiệu suất, tiêu thụ bộ nhớ và pin?
Duna

@Duna đó là 5 năm trước, hiện tại chúng ta có thể sử dụng glide chẳng hạn
Alex Zaraos

22

Tôi đã giải quyết vấn đề bằng cách chia hoạt hình gif thành các khung trước khi lưu nó vào điện thoại, vì vậy tôi sẽ không phải đối phó với nó trong Android.

Sau đó, tôi tải xuống mọi khung hình trên điện thoại, tạo Drawable từ nó và sau đó tạo AnimationDrawable - rất giống với ví dụ từ câu hỏi của tôi


2
Đó là cách tài liệu xử lý hình ảnh động.
RichieHH

16

tôi tìm thấy một cách rất dễ dàng, với một ví dụ làm việc đơn giản và tốt đẹp ở đây

hiển thị widget hoạt hình

Trước khi làm cho nó hoạt động, có một số mánh phải làm trong mã

TRONG NHỮNG ĐIỀU SAU ĐÂY

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

chỉ cần thay thế

setContentView(new MYGIFView());

trong

setContentView(new MYGIFView(this));

VÀ VÀO

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

Cung cấp tệp hoạt hình gif của riêng bạn

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

Thay thế dòng đầu tiên trong

public MYGIFView(Context context) {

theo tên của lớp ...

Sau khi thực hiện những thay đổi nhỏ này, nó sẽ hoạt động như đối với tôi ...

hy vọng điều này giúp đỡ


2
Trên phiên bản Android nào bạn đã thử điều này? Tôi đã thử trên phiên bản Android 2.2 và 2.3 nhưng nó trả về đối tượng Movie null. Bất kỳ ý tưởng về những gì có thể sai?
Ashwini Shahapurkar

16
Hãy làm sạch câu trả lời này, nó là như vậy, ngẫu nhiên.
taxeeta

2
vấn đề với câu trả lời là gì? Tôi vừa cung cấp một liên kết và một số sửa chữa cần thiết để làm cho nó hoạt động
Xuất hiện vào

10

Các cách hiển thị GIF động trên Android:

  • Lớp học phim. Như đã đề cập ở trên, nó khá lỗi.
  • WebView. Nó rất đơn giản để sử dụng và thường hoạt động. Nhưng đôi khi nó bắt đầu hoạt động sai và nó luôn nằm trên một số thiết bị tối nghĩa mà bạn không có. Ngoài ra, bạn không thể sử dụng nhiều phiên bản trong bất kỳ loại chế độ xem danh sách nào, vì nó thực hiện mọi thứ cho bộ nhớ của bạn. Tuy nhiên, bạn có thể coi nó như một cách tiếp cận chính.
  • Mã tùy chỉnh để giải mã gifs thành bitmap và hiển thị chúng dưới dạng Drawable hoặc ImageView. Tôi sẽ đề cập đến hai thư viện:

https://github.com/koral--/android-gif-drawable - bộ giải mã được triển khai trong C, vì vậy nó rất hiệu quả.

https://code.google.com.vn/p/giffiledecoder - bộ giải mã được triển khai trong Java, vì vậy làm việc với nó dễ dàng hơn. Vẫn hợp lý hiệu quả, ngay cả với các tập tin lớn.

Bạn cũng sẽ tìm thấy nhiều thư viện dựa trên lớp GifDecoder. Đó cũng là một bộ giải mã dựa trên Java, nhưng nó hoạt động bằng cách tải toàn bộ tệp vào bộ nhớ, do đó, nó chỉ áp dụng cho các tệp nhỏ.


10

Tôi đã có một thời gian thực sự khó khăn để gif hoạt hình hoạt động trong Android. Tôi chỉ có hai việc sau:

  1. Xem trên web
  2. Ion

WebView hoạt động tốt và thực sự dễ dàng, nhưng vấn đề là nó làm cho chế độ xem tải chậm hơn và ứng dụng sẽ không phản hồi trong một giây. Tôi không thích điều đó. Vì vậy, tôi đã thử các cách tiếp cận khác nhau (DID NOT WORK):

  1. ImageViewEx không được dùng nữa!
  2. picasso không tải gif hoạt hình
  3. android-gif-drawable trông rất tuyệt, nhưng nó gây ra một số vấn đề NDK có dây trong dự án của tôi. Nó khiến thư viện NDK địa phương của tôi ngừng hoạt động và tôi không thể sửa nó

Tôi đã có một vài lần qua lại với Ion; Cuối cùng, tôi có nó hoạt động, và nó thực sự rất nhanh :-)

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

Tôi đã có cùng các vấn đề liên quan đến NDK với android-gif-drawable.
RominaV

Xin chào @RominaV, Bạn đã sử dụng thanh tiến trình trong Ion khi tải gif chưa, vì tôi cần hiển thị tiến trình khi tải gif.
patel135

9

Lướt 4.6

1. Để tải gif

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

2. Để có được đối tượng tập tin

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

Thư viện tải hình ảnh cho Android, được đề xuất bởi Google.

  • Glide khá giống với Picasso nhưng điều này nhanh hơn Picasso rất nhiều.
  • Glide tiêu thụ ít bộ nhớ hơn Picasso.

Glide có gì nhưng Picasso thì không

Khả năng tải GIF Animation vào ImageView đơn giản có thể là tính năng thú vị nhất của Glide. Và vâng, bạn không thể làm điều đó với Picasso. Một số liên kết quan trọng-nhập mô tả hình ảnh ở đây

  1. https://github.com/bumptech/glide
  2. http://inthecheesefactory.com/blog/get-to-ledge-glide-recommends-by-google/en

Google giới thiệu Glid ở đâu?
Derzu

1
Xem điều này, nơi nhóm Nhà phát triển Android đã sử dụng Glide trong ứng dụng mẫu của họ. developer.android.com/samples/XYZTouristAttraction/Application/,
Shoeb Siddique

1
'Glide khá giống với Picasso nhưng điều này nhanh hơn Picasso rất nhiều' và 'Glide tiêu thụ ít bộ nhớ hơn Picasso'. Xin lỗi tôi không hài lòng với những ý tưởng này, vui lòng thích liên kết này: Medium.com/@multidots/glide-vs-picasso-930eed42b81d . Btw, tôi không thể kiểm tra Glide 4.0 ngay bây giờ vì không thể nâng cấp bản dựng lên 3.0.1 (kết nối Internet chậm); nhưng tôi đã thử nghiệm Glide 3.5.2 khi hiển thị gif, nó hoạt động nhưng không hoàn hảo như tôi mong đợi trên img lớn (nó nhấp nháy) và đây cũng là một vấn đề phổ biến. Xin CMIW.
Nguyễn Tấn Đạt

7

Sử dụng ImageViewEx , một thư viện giúp sử dụng gif dễ dàng như sử dụng ImageView.


Điều này đã bị phản đối
Martin Marconcini

Tôi đã xem qua mã thư viện này, nó sẽ tốt trong 2 năm hoặc lâu hơn.
NightSkyCode

1
Vâng, tôi nghĩ rằng nó tương đối tốt, chỉ cần chỉ ra rằng tác giả đã quyết định từ chối nó. (và do đó không duy trì nó), chỉ ra rằng chúng ta nên sử dụng một cái gì đó như Picasso, điều này thật kỳ lạ, bởi vì Picasso là một trình tải xuống hình ảnh và sẽ không giúp bạn khi hiển thị gif hoạt hình nữa so với bất kỳ tải xuống / bộ đệm công cụ ngoài kia.
Martin Marconcini

6

Hãy thử điều này, mã dưới đây hiển thị tệp gif trong thanh tiến trình

load_activity.xml (trong thư mục Bố cục)

<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 (trong thư mục drawable)

Ở đây tôi đặt black_gif.gif (trong thư mục drawable), bạn có thể đặt gif của riêng bạn ở đây

<?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 (trong thư mục 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);

    }

}

Tôi thấy bạn xoay gif. Tại sao?
AlikElzin-kilaka

Làm thế nào bạn có thể đặt gif trong thư mục drawable?
Apurva

6

Không ai đã đề cập đến thư viện Ion hoặc Glide . họ làm việc rất tốt

Nó dễ xử lý hơn so với WebView.


5

Tôi đã thành công với giải pháp được đề xuất trong bài viết này , một lớp được gọi GifMovieView, trong đó biểu hiện một Viewcái mà sau đó có thể được hiển thị hoặc thêm vào một cụ thể ViewGroup. Kiểm tra các phương pháp khác được trình bày trong phần 2 và 3 của bài viết được chỉ định.

Hạn chế duy nhất của phương pháp này là khử răng cưa trên phim không tốt (phải là tác dụng phụ của việc sử dụng MovieLớp Android "mờ ám" ). Sau đó, tốt hơn hết bạn nên đặt nền thành màu đơn sắc trong GIF hoạt hình của mình.


4

Một số suy nghĩ về ví dụ BitmapDecode ... Về cơ bản, nó sử dụng lớp Phim cổ trang nhưng khá kỳ công từ android.graphics. Trên các phiên bản API gần đây, bạn cần tắt tăng tốc phần cứng, như được mô tả ở đây . Đó là segfaulting cho tôi khác.

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

Dưới đây là ví dụ BitmapDecode được rút ngắn chỉ với phần GIF. Bạn phải tạo Widget (View) của riêng bạn và tự vẽ nó. Không hoàn toàn mạnh mẽ như 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();
            }
        }
    }
}

Có thể tìm thấy 2 phương thức khác, một phương pháp với ImageView khác với WebView trong hướng dẫn tốt này . Phương thức ImageView sử dụng gifview được cấp phép của Apache từ Google Code.


1
@luboz bạn có thể vui lòng cho tôi biết phương pháp nào tốt cho hiệu suất Android ... tôi muốn sử dụng gif hoạt hình cho thanh tải màn hình giật gân. vì vậy bạn có thể đề nghị phương pháp nào là tốt hơn. Ngoài ra tôi muốn biết rằng bằng cách sử dụng phương pháp xem hình ảnh, nó có thể sử dụng thuộc tính loại tỷ lệ không?
Hoán đổi-IOS-Android

4

@PulumNull đã đưa ra giải pháp tốt, nhưng nó không hoàn hảo. Nó không hoạt động trên một số thiết bị có tệp lớn và hiển thị hoạt hình Gif có lỗi với các khung delta trên phiên bản ICS trước. Tôi tìm thấy giải pháp mà không có lỗi này. Đây là thư viện với giải mã gốc thành drawable: android-gif-drawable .


2

Đặt nó vào WebView, nó phải có khả năng hiển thị chính xác, vì trình duyệt mặc định hỗ trợ các tệp gif. (Froyo +, nếu tôi không nhầm)


Đây không phải là sự thật. Không phải tất cả các trình duyệt đều hỗ trợ GIF.
RichieHH

4
Hy vọng rằng chúng tôi không cần tất cả các trình duyệt ... Trình duyệt chứng khoán hỗ trợ nó kể từ Android 2.2, vì vậy đừng đánh giá thấp tôi. Một WebView chắc chắn sẽ hiển thị GIF!
keybee

2

Có hai tùy chọn để tải ảnh động vào ứng dụng Android của chúng tôi

1) Sử dụng Glide để tải gif vào một 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) Sử dụng html để tải gif vào WebView

Tạo html với địa chỉ tệp .gif:

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

lưu trữ tệp này vào thư mục tài sản:

nhập mô tả hình ảnh ở đây

Tải html này vào WebView của ứng dụng của bạn:

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

Đây là một ví dụ đầy đủ của hai lựa chọn này .

nhập mô tả hình ảnh ở đây


2

Chỉ dành cho API Android (Android Pie) 28 và +

sử dụng AnimatedImageDrawable như

// 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()

Mã XML, thêm 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 là con của Drawable và được tạo bởi ImageDecoder.decodeDrawable

ImageDecoder.decodeDrawablemà yêu cầu thêm về thể hiện ImageDecoder.Sourceđược tạo bởi ImageDecoder.createSource.

ImageDecoder.createSourcechỉ có thể lấy nguồn làm tên, ByteBuffer, File, resourceId, URI, ContentResolver để tạo đối tượng nguồn và sử dụng nó để tạo AnimatedImageDrawablenhư Drawable(cuộc gọi đa hình)

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)

Lưu ý: Bạn cũng có thể tạo Bitmapbằng ImageDecoder # decodeBitmap .

Đầu ra:

AnimatedDrawable cũng hỗ trợ thay đổi kích thước, khung và màu


1

Tôi nghĩ rằng thư viện tốt hơn để xử lý các tập tin gif là cái này: bởi koral

Đã sử dụng nó và tôi thành công và thư viện này được dành riêng cho GIF; nhưng nơi mà picasso và glide là khung hình ảnh mục đích chung ; Vì vậy, tôi nghĩ rằng các nhà phát triển của thư viện này đã hoàn toàn tập trung vào các tập tin gif



1

Chỉ muốn thêm rằng lớp Phim hiện không được dùng nữa.

Lớp này không được dùng ở cấp độ API P.

Nên sử dụng cái này

AnimatedImageDrawable

Drawable để vẽ hình ảnh hoạt hình (như GIF).


1

Tạo một gói có tên là Ut Utils, trong thư mục src và tạo một lớp có tên là 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");
        }
    }
}

Bây giờ hãy xác định GifImageView trong tệp MainActivity: 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);
    }
}

Bây giờ Tệp phần 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>

Mã nguồn: ví dụ Android


Làm thế nào để thay đổi kích thước hình ảnh, xin vui lòng
The Dead Guy

0

Trước hết, trình duyệt Android nên hỗ trợ GIF động. Nếu không thì đó là một lỗi! Có một cái nhìn vào các vấn đề theo dõi.

Nếu bạn đang hiển thị những GIF động này bên ngoài trình duyệt thì đó có thể là một câu chuyện khác. Để làm những gì bạn yêu cầu sẽ yêu cầu thư viện bên ngoài hỗ trợ giải mã GIF hoạt hình.

Cổng gọi đầu tiên sẽ là nhìn vào API Java2D hoặc JAI (Hình ảnh nâng cao Java), mặc dù tôi sẽ rất ngạc nhiên nếu Android Dalvik sẽ hỗ trợ các thư viện đó trong Ứng dụng của bạn.


một số thiết bị không hiển thị ảnh động, ngay cả trên trình duyệt web. như một ví dụ, tôi biết rằng galaxy mini với Android 2.3.6 không hiển thị chúng.
nhà phát triển Android

0

Tương tự như những gì @Leonti đã nói, nhưng với chiều sâu hơn một chút:

Những gì tôi đã làm để giải quyết vấn đề tương tự là mở GIMP, ẩn tất cả các lớp trừ một lớp, xuất nó thành hình ảnh của chính nó, sau đó ẩn lớp đó và bỏ ẩn lớp tiếp theo, v.v., cho đến khi tôi có các tệp tài nguyên riêng lẻ cho mỗi lớp . Sau đó, tôi có thể sử dụng chúng làm khung trong tệp XML AnimationDrawable.


1
Bạn có thể sử dụng gifsicle để trích xuất các khung nếu bạn không có nhiều thời gian đó. Ngoài ra python hoặc bash rất tiện dụng khi tạo tệp xml.
Lubosz

0

Tôi đã giải quyết điều này bằng cách chia gif trong khung và sử dụng hoạt hình Android tiêu chuẩn


0

Một cái gì đó tôi đã làm để hiển thị gifs trong ứng dụng. Tôi đã mở rộng ImageView để mọi người có thể sử dụng các thuộc tính của nó một cách tự do. Nó có thể hiển thị gifs từ url hoặc từ thư mục tài sản. Thư viện cũng giúp dễ dàng mở rộng các lớp kế thừa từ nó và mở rộng nó để hỗ trợ các phương thức khác nhau để khởi tạo gif.

https://github.com/Gavras/GIFView

Có một hướng dẫn nhỏ trên trang github.

Nó cũng được xuất bản trên Android Arsenal:

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

Sử dụng ví dụ:

Từ 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" />

Trong hoạt động:

    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) {

        }
});

Đặt gif theo chương trình:

mGifView.setGifResource("asset:gif1");

0

Cách dễ nhất - Có thể xem xét mã dưới đây

Chúng ta có thể tận dụng lợi thế của Imageview setImageResource, tham khảo mã bên dưới cho cùng.

Mã dưới đây có thể được sử dụng để hiển thị hình ảnh như gif incase nếu bạn có nhiều hình ảnh phân chia của gif. Chỉ cần chia gif thành png riêng từ một công cụ trực tuyến và đặt hình ảnh có thể vẽ như thứ tự dưới đây

image_1.png, image_2.png, v.v.

Có xử lý để thay đổi hình ảnh năng động.

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

Cách dễ dàng để hiển thị GIF động trực tiếp từ URL đến bố cục ứng dụng của bạn là sử dụng lớp WebView.

Bước 1: Trong XML bố trí của bạn

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

Bước 2: Trong hoạt động của bạn

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

Bước 3: Trong Manifest.XML, hãy cho phép Internet

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

Bước 4: Trong trường hợp bạn muốn làm cho nền GIF của bạn trong suốt và làm cho GIF phù hợp với Bố cục của bạn

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


Cảm ơn vì cách giải quyết nhưng nhà phát triển đáng kể có thể không muốn kết xuất không phải do bản địa do một số tác động như ảnh hưởng đến bộ nhớ, sử dụng CPU và tuổi thọ pin
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());

      }
    }
  }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.