eschao / android-PageFlip

3D Style Page Flip on Android
Apache License 2.0
1.74k stars 262 forks source link

How to get Bitmaps in an order other than displaying Randomly ? #40

Closed sayansubhrabanerjee closed 6 years ago

sayansubhrabanerjee commented 6 years ago

Hi

Could you please let me know how can I get the bitmaps in an order ? In the LoadBitmapTask class there is a method getRandomBitmap() which is generating bitmaps randomly. How the code should be written if I want to display them in a specific order ? (like the pages in book, which has an order).

ja2375 commented 6 years ago

It took some time for me as well to figure that out. In the PageRender class, the drawPage method takes an argument which represents the number of the page to draw. I achieved the order of the pages by passing that argument all the way to the getRandomBitmap method of the class LoadBitmapTask which i renamed and changed it a bit. Now it looks as follows:

 /**
     * Load next image
     *
     * @param number of page to load
     * @return correctly ordered bitmap
     */
    private Bitmap getNextBitmap(int number) {
        int resId = mPortraitBGs[number - 1];
        Bitmap b = BitmapFactory.decodeResource(mResources, resId);
        if (mIsLandscape) {
            Matrix matrix = new Matrix();
            matrix.postRotate(90);
            Bitmap lb = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(),
                    matrix, true);
            b.recycle();
            return lb;
        }

        return b;
    }

This way the bitmap order should be the same as you have it in you initialization array. Hope that helps :)

sayansubhrabanerjee commented 6 years ago

Thanks for your input! Based on your answer I need a few clarification:

  1. How are you passing this "number" argument of drawPage(int number) from Single/DoublePageRender to LoadBitmapTask ?

  2. From where should I call this new method getNextBitmap(int number) and what should be the argument value while calling this method ?

  3. As you have mentioned in this new method:

int resId = mPortraitBGs[number - 1];

But mPortraitBGs[][] is basically a 2D array. So if I want to maintain 2D array like following:

int resId = mPortraitBGs[mBGSizeIndex][number - 1];

Will this work ?

It'd also be great if you could provide those modified class files. I could integrate them in my project and try understanding the code.

ja2375 commented 6 years ago

This is what i did exactly:

  1. First of all, in LoadBitmapTask class i changed the getBitmap() method to look as follows:

    public Bitmap getBitmap(int number) {
        return getNextBitmap(number);
    }

    Note that i removed all the code that is supposed to run in another thread as it is not really needed.

  2. In that same class, change the getRandomBitmap() method to what i wrote in my last comment but leaving the array bidimensional as you mentioned. That should work.

private Bitmap getNextBitmap(int number) {
        int resId = mPortraitBGs[mBGSizeIndex][number - 1];
        Bitmap b = BitmapFactory.decodeResource(mResources, resId);
        if (mIsLandscape) {
            Matrix matrix = new Matrix();
            matrix.postRotate(90);
            Bitmap lb = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(),
                    matrix, true);
            b.recycle();
            return lb;
        }

        return b;
    }
  1. In SinglePageRender as well as in DoublePagesRender classes, in the drawPage(int number) method change the line Bitmap background = LoadBitmapTask.get(mContext).getBitmap(); to Bitmap background = LoadBitmapTask.get(mContext).getBitmap(number); and you should be good to go.

Note that at this point the IDE will complain at compile time because there is another call to getBitmap() method that actually needs an argument. But, as i said before, i deleted all the code that runs in another thread so this call got deleted as well.

I leave here my LoadBitmapTask class so you can take a look in case something is not clear at all:

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;

public final class LoadBitmapTask {

    private final static String TAG = "LoadBitmapTask";
    private static LoadBitmapTask __object;

    private int mQueueMaxSize;
    private Resources mResources;
    private int[] mPortraitBGs;
    private boolean mIsLandscape;

    public static LoadBitmapTask get(Context context) {
        if (__object == null) {
            __object = new LoadBitmapTask(context);
        }
        return __object;
    }

    public static void destroyInstance(){
        if (__object != null)
            __object = null;
    }

    private LoadBitmapTask(Context context) {
        mResources = context.getResources();
        mIsLandscape = false;
        mQueueMaxSize = 1;

        // init all available bitmaps
        mPortraitBGs = new int[] {R.drawable.pag01, R.drawable.pag02, R.drawable.pag03,
                                    R.drawable.pag04, R.drawable.pag05, R.drawable.pag06,
                                    R.drawable.pag07, R.drawable.pag08, R.drawable.pag09,
                                    R.drawable.pag10, R.drawable.pag11, R.drawable.pag12,
                                    R.drawable.pag13, R.drawable.pag14, R.drawable.pag15,
                                    R.drawable.pag16, R.drawable.pag17, R.drawable.pag18,
                                    R.drawable.pag19, R.drawable.pag20, R.drawable.pag21,
                                    R.drawable.pag22, R.drawable.pag23, R.drawable.pag24,
                                    R.drawable.pag25, R.drawable.pag26, R.drawable.pag27,
                                    R.drawable.pag28, R.drawable.pag29, R.drawable.pag30,
                                    R.drawable.pag31, R.drawable.pag32, R.drawable.pag33,
                                    R.drawable.pag34};
    }

    /**
     * Acquire a bitmap to show
     * <p>If there is no cached bitmap, it will load one immediately</p>
     *
     * @return
     */
    public Bitmap getBitmap(int number) {
        return getNextBitmap(number);
    }

    /**
     * Set bitmap width , height and maximum size of cache queue
     *
     * @param w width of bitmap
     * @param h height of bitmap
     * @param maxCached maximum size of cache queue
     */
    public void set(int w, int h, int maxCached) {
        mIsLandscape = w > h;

        if (maxCached != mQueueMaxSize) {
            mQueueMaxSize = maxCached;
        }
    }

    /**
     * Load next image
     *
     * @param number
     * @return
     */
    private Bitmap getNextBitmap(int number) {
        int resId = mPortraitBGs[number - 1];
        Bitmap b = BitmapFactory.decodeResource(mResources, resId);
        if (mIsLandscape) {
            Matrix matrix = new Matrix();
            matrix.postRotate(90);
            Bitmap lb = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(),
                    matrix, true);
            b.recycle();
            return lb;
        }

        return b;
    }
}

Another thing to point out is that i made the mPortraitBGs array 1D and i changed images to drawable-nodpi folder so Android itself rescales the images according to device density which i believe by doing that images won't take a lot of space on memory when the app is running.

sayansubhrabanerjee commented 6 years ago

That's an amazing answer!

I have understood the code snippet pretty well.

Along with these modifications I have disabled the following two lines from SampleActivity as well :

LoadBitmapTask.get(this).start(); //disabled this from onResume() LoadBitmapTask.get(this).stop(); //disabled this from onPause()

I haven't modified anything else. And the code is working like a charm!!

Let me get back to you again if I come across any other issues on this.

Do you have any blogs ? I believe I can learn from that if you have any blogs / YouTube videos / or anything else.

ja2375 commented 6 years ago

Hey, sorry for late reply, I was really busy with work untill now. I'm glad the answer helped you :)

I do have a blog but it's in Spanish and i'm not posting too frequently nor it's about coding xD No Youtube channels nor any social network. I don't really like them, sorry.

But if you run into any issues just let me know via email if you want and i will be happy to help. My email address is on my profile here.

Good luck!

sayansubhrabanerjee commented 6 years ago

That's fine.

I'll mail you if I come across any issues. Thanks again. :)