Search code examples
androidandroid-viewpagerandroid-bitmap

Android convert contents of ViewPager to Bitmap


I have a ViewPager displaying a series of graphs. I want to convert the contents of the ViewPager as the user sees it to a Bitmap which can be shared. I have acheived this, but if there is more than one graph in the series it doesn't always take the one currently displayed. Usually it takes the one furthest right, which is the one with the highest index (eg 2 if there are 3 items). Sometimes it's taken the one furthest left, I haven't managed to understand the circumstances for one or the other.

I'm an amateur developer, and suspect I am missing some basic information about how Viewpagers work...

How can I convert the contents of the current viewpager item on display to the bitmap?

graphs as seen by a user

The viewpager is set up with a custom PagerAdaptor which takes in data from a Room database as LiveData via a ViewwModel, sorts it, and displays it as a series of graph. Here are some code snippets relating to the ViewPager and Bitmap. Let me know if more information is needed for my question to make sense.

Code:

 public class ResultsGraphFragment extends Fragment {
      ViewPager viewPager;

      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
           viewPager = root.findViewById(R.id.viewPager);

           //do this when viewpager moved.
           viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
           @Override
           public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

           }

           @Override
           public void onPageSelected(int position) {
               displayChevrons();
           }

           @Override
           public void onPageScrollStateChanged(int state) {

           }
       });

...

 private void shareImage() {
    Intent i = new Intent(Intent.ACTION_SEND);
    i.setType("image/*");
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    i.putExtra(Intent.EXTRA_STREAM, getImageUri(getContext(), getBitmapFromView(viewPager)));
    try {
        startActivity(Intent.createChooser(i, getString(R.string.share_description_image_only)));
    } catch (android.content.ActivityNotFoundException ex) {
        ex.printStackTrace();
    }
}

public static Bitmap getBitmapFromView(View view) {
    Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(returnedBitmap);
    Drawable bgDrawable =view.getBackground();
    if (bgDrawable!=null)
        bgDrawable.draw(canvas);
    else
        canvas.drawColor(Color.WHITE);
    view.draw(canvas);
    return returnedBitmap;
} 

public Uri getImageUri(Context inContext, Bitmap inImage) {
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
    return Uri.parse(path);
}

Solution

  • It seems that I was asking the wrong question for my problem. The ViewPager doesn't necessarily know what it is displaying, that is the PagerAdapter's job.

    To convert the contents of my ViewPager item to a Bitmap, I needed to reference the View(s) within this that were being displayed.

    I found my solution as per Shadab Ansari's answer to this question: Getting current view from ViewPager

    I tagged the whole view after inflating the layout in "instantiate item" in the custom PagerAdapter, then used viewPager.findViewWithTag() to find the view corresponding to the current position.

    In the PagerAdapter:

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        LayoutInflater layoutInflater = LayoutInflater.from(mContext);
        View itemView = layoutInflater.inflate(R.layout.list_item_result_graph, container, false);
        //tag item view so that the correct graph can be found and shared from ResultsGraphFragment
        itemView.setTag("View"+position);
    

    My new shareImage() method:

    private void shareImage() {
        Intent i = new Intent(Intent.ACTION_SEND);
        i.setType("image/*");
        int currentItem = viewPager.getCurrentItem();
        View v = viewPager.findViewWithTag("View"+currentItem);
        if (v != null) {
            i.putExtra(Intent.EXTRA_STREAM, getImageUri(getContext(), getBitmapFromView(v)));
            try {
                startActivity(Intent.createChooser(i, getString(R.string.share_description_image_only)));
            } catch (android.content.ActivityNotFoundException ex) {
                ex.printStackTrace();
            }
        } else {
            Toast.makeText(this.getContext(), "error sharing image", Toast.LENGTH_SHORT).show();
        }
    }