雪碧图在Android上的使用

0 阅读2分钟

一. 什么是雪碧图 简单解释,就是把很多小图集中到一起,做到一张大图片上。 今天来说下如何显示雪碧图。 原雪碧图:

sprite_pictures.webp

使用雪碧图实现的动画效果

Screen_recording_20260218_100951.gif

二.雪碧图的用法

  1. 读取雪碧图
public static Bitmap getBitmapFromAssets(@NonNull Context context, @NonNull String filePath){
    AssetManager assetManager = context.getAssets();
    InputStream inputStream = null;
    Bitmap spriteBitmap = null;
    try {
        inputStream = assetManager.open(filePath);
        spriteBitmap = BitmapFactory.decodeStream(inputStream);
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        if(inputStream!=null){
            try{
                inputStream.close();
            }catch (IOException ioException){
                ioException.printStackTrace();
            }

        }
    }
    return spriteBitmap;
}

2. 获取雪碧图后,将图片切割后,放到数组中

public static ArrayList<Bitmap> getPlayArrayList(@NonNull Bitmap spriteBitmap,
                                                 int bitmapFrameNum, int bitmapFrameW, int bitmapFrameH, int countX, int countY,
                                                 boolean isScale, int scaleFactor){
    ArrayList<Bitmap> bitmaps = new ArrayList<>();

    for(int i=0;i<countY;i++){
        for(int j=0;j<countX;j++){
            Bitmap currentFrame = Bitmap.createBitmap(spriteBitmap,bitmapFrameW*j,bitmapFrameH*i,
                    bitmapFrameW,bitmapFrameH);
            if(isScale){
                currentFrame = Bitmap.createScaledBitmap(currentFrame,bitmapFrameW*scaleFactor,
                        bitmapFrameH*scaleFactor,true);
            }
            bitmaps.add(currentFrame);
            if(bitmaps.size()>=bitmapFrameNum){
                break;
            }
        }
    }
    return bitmaps;
}

3. 动画

public static void startImageAnimation(@NonNull Context context,@NonNull AnimationDrawable animation,ImageView imageView,ArrayList<Bitmap> bitmaps,int duration){
    // create animation programmatically
    animation.setOneShot(false); // repeat animation
    for(int i=0;i<bitmaps.size();i++){
        animation.addFrame(new BitmapDrawable(context.getResources(),bitmaps.get(i)),duration);
    }
    // load animation on image
    if (Build.VERSION.SDK_INT < 16) {
        imageView.setBackgroundDrawable(animation);
    } else {
        imageView.setBackground(animation);
    }
    // start animation on image
    imageView.post(new Runnable() {

        @Override
        public void run() {
            animation.start();
        }

    });
}
public static void stopImageAnimation(@NonNull ImageView imageView,@NonNull AnimationDrawable animation){
    imageView.post(new Runnable() {
        @Override
        public void run() {
            animation.stop();
        }
    });
}

4. 使用ImageView 进行展示

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/display_text_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="雪碧图"
        android:layout_marginTop="50dp"
        android:layout_marginStart="30dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <ImageView
        android:id="@+id/image_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_marginStart="30dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/display_text_id" />
    <Button
        android:id="@+id/start_play_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="开始"
        android:layout_marginTop="20dp"
        android:layout_marginStart="30dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/image_id" />
    <Button
        android:id="@+id/stop_play_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="停止"
        android:layout_marginTop="20dp"
        android:layout_marginStart="30dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/start_play_id" />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.example.spriteapplication;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.widget.ImageView;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;

import com.aomomo.sprite.SpriteBitmapUtils;
import com.example.spriteapplication.databinding.ActivityMainBinding;

import java.util.ArrayList;


public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding mBinding;
    public static ArrayList<Bitmap> mBitmaps;
    private AnimationDrawable animation;
    // frame width
    private static final int FRAME_W = 400;
    // frame height
    private static final int FRAME_H = 400;
    // number of frames
    private static final int NB_FRAMES = 65;
    // nb of frames in x
    private static final int COUNT_X = 8;
    // nb of frames in y
    private static final int COUNT_Y = 9;
    // scale factor for each frame
    private static final int SCALE_FACTOR = 3;
    // frame duration
    private static final int FRAME_DURATION = 40; // in ms !
    private Context mContext = null;
    private Handler mHandler = null;
    private ImageView mImageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        mBinding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(mBinding.getRoot());
        mImageView = mBinding.imageId;
        mContext = this;
        animation = new AnimationDrawable();
        mHandler = new Handler(getMainLooper()){
            @Override
            public void handleMessage(android.os.Message msg) {
                super.handleMessage(msg);
                switch (msg.what){
                    case 0:
                        if(mBitmaps != null) {
                            mBinding.imageId.setImageBitmap(mBitmaps.get(0));
                        }
                        break;
                }

            }
        };
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                initBitmapsResource(mContext);
                mHandler.sendEmptyMessage(0);
            }
        };
        new Thread(runnable).start();

        mBinding.startPlayId.setOnClickListener(v -> {
            if(mBitmaps != null) {
                mBinding.imageId.setImageBitmap(null);
                SpriteBitmapUtils.getInstance().startImageAnimation(mContext, animation, mImageView, mBitmaps, FRAME_DURATION);
            }
        });
        mBinding.stopPlayId.setOnClickListener(v -> {
            if(mBitmaps != null) {
                SpriteBitmapUtils.getInstance().stopImageAnimation(mImageView,animation);
                mBinding.imageId.setImageBitmap(mBitmaps.get(0));
                mBinding.imageId.setBackground(null);
            }
        });

    }
    public static void initBitmapsResource(Context context){
        // load bitmap from assets
        String spriteFilePath = "sprite_pictures.webp";
        Bitmap birdBmp = SpriteBitmapUtils.getInstance().getBitmapFromAssets(context, spriteFilePath);
        mBitmaps = SpriteBitmapUtils.getInstance().getPlayArrayList(birdBmp, NB_FRAMES, FRAME_W, FRAME_H, COUNT_X,
                COUNT_Y, false, SCALE_FACTOR);
    }
}

三. 完整代码 完整代码参考: github.com/lixiangdeba…