Emil Adz
Emil Adz

Reputation: 41129

How to get current view pager view without tags?

I have a view pager in which each page is a custom view ( ...and not a Fragment) that I'm inflating using a LayoutInflator. Each custom view has an ImageView inside it that is populated with an image from web using the Glide library.

My task is while the user scrolls throw the view pager each time he changes pages I need to retrieve the Bitmap that is populating the currently shown ImageView.

I tried using the set the OnPageChangeListener on the view pager and use the onPageSelected method to get the current view using the viewPager.getChildAt() method or viewPager.getFocusedChild().

Here is the code:

Activity:

public class TimelineMomentActivity extends ActivityBase implements ViewPager.OnPageChangeListener, View.OnClickListener,
    TimelineCommentsGetRequest.Callback, CreativeHandler.CreativeHandleCallback {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    AppInstance.sharedInstance().getBus().register(this);

    mShouldSaveToDB = AppInstance.sharedInstance().isSelf();
    mStory = getIntent().getParcelableExtra(StoryDB.KEY_NAME);

    final String storyID = getIntent().getStringExtra(KEY_STORY_ID);
    final String momentID = getIntent().getStringExtra(KEY_MOMENT_ID);
    mSelectedIndex = getIntent().getIntExtra(ARG_SELECTED_INDEX, 0);

    if (!mShouldSaveToDB) {
        if (mStory == null) {
            sendRequest(storyID, momentID);
        } else {
            mMoments = mStory.getMoments();
            setViewPager();
        }
    } else {
        if (mStory != null) {
            mStoryDB = DBManager.getStory(mStory.getID());
        } else {
            mStoryDB = DBManager.getStory(storyID);
        }
        if (mStoryDB == null) {
            sendRequest(storyID, momentID);
        } else {
            setGlobalDataWithStoryDB();
            setViewPager();
        }
    }

    mCreativeHandler = new CreativeHandler(this, this);

    File cacheDir = Glide.getPhotoCacheDir(this, MyGlideModule.DISK_IMAGE_CACHE_NAME);
    File[] filesList = cacheDir.listFiles();
    for (File cachedFile : filesList) {
        Log.d(TAG, "cachedFileName = " + cachedFile.getName() + " ,path = " + cachedFile.getAbsolutePath());
    }
}

@Override
public Toolbar setToolbar() {
    Toolbar mToolbar = (Toolbar) findViewById(R.id.mToolbar);
    mToolbar.setBackgroundColor(getResources().getColor(R.color.black_color));
    mToolbar.setVisibility(View.VISIBLE);
    return mToolbar;
}

@Override
public void findViews() {
    setContentView(R.layout.timeline_moment_activity);
    mVp = (HackyViewPager) findViewById(R.id.mVp);
    mTvName = (TextView) findViewById(R.id.mTvName);
    mTvContent = (TextView) findViewById(R.id.mTvVpContent);
    mTvDate = (TextView) findViewById(R.id.mTvUsername);
    mTvNumberOfLikes = (TextView) findViewById(R.id.mTvNumberOfLikes);
    mBtnLike = (ImageView) findViewById(R.id.mBtnLike);
    mTvNumberOfComments = (TextView) findViewById(R.id.mTvNumberOfComments);
    mBtnComments = (ImageView) findViewById(R.id.mBtnComments);
    mTvNumberOfShares = (TextView) findViewById(R.id.mTvNumberOfShares);
    mBtnShare = (ImageView) findViewById(R.id.mBtnShare);

    mBtnLike.setOnClickListener(this);
    mTvNumberOfLikes.setOnClickListener(this);

    mBtnShare.setOnClickListener(this);
    mTvNumberOfShares.setOnClickListener(this);

    mBtnComments.setOnClickListener(this);
    mTvNumberOfComments.setOnClickListener(this);
}

…..

private void setGlobalDataWithStoryDB () {
    if (mStoryDB == null) {
        return;
    }
    mMomentsDB = mStoryDB.getMoments();
    mStory = mStoryDB.converter();
    mMoments = mStory.getMoments();
}

// MARK: View Pager

private void setViewPager() {
    mAdapter = new TimelineMomentPagerAdapter(this, mMoments, mStoryDB);
    mVp.setOffscreenPageLimit(-1);
    mVp.addOnPageChangeListener(this);
    mVp.setAdapter(mAdapter);
    mVp.setCurrentItem(mSelectedIndex);
}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    if (mMoments.isEmpty()) {
        return;
    }

    /*View currentView = mVp.getChildAt(position);
    if (currentView != null) {
        mAdapter.setBitmap(currentView);
    } else {
        currentView = mVp.getFocusedChild();
        if (currentView != null) {
            mAdapter.setBitmap(currentView);
        }
    }*/

    mSelectedIndex = position;
    final MomentPojo moment = mMoments.get(position);

    if (getSupportActionBar() != null)
        getSupportActionBar().setTitle(mStory.getTitle() + " " + (position + 1) + "/" + mMoments.size());

    mTvNumberOfShares.setText(""); // TODO: No API for number of shares

    handleLikeState(moment);
    handleComments(moment);
    mTvName.setText(moment.getOwnerName());
    if (moment.getTimestamp() != null) {
        mTvDate.setText(Utility.timestampToDateString(moment.getTimestamp()));
    } else {
        mTvDate.setVisibility(View.INVISIBLE);
    }

    if (moment.getTitle().equals("")) {
        mTvContent.setVisibility(View.GONE);
    } else {
        mTvContent.setVisibility(View.VISIBLE);
        mTvContent.setText(moment.getTitle());
    }
}

@Override
public void onPageSelected(int position) {
    View currentView = mVp.getChildAt(1);
    if (currentView != null) {
        mAdapter.setBitmap(currentView);
    } else {
        currentView = mVp.getFocusedChild();
        if (currentView != null) {
            mAdapter.setBitmap(currentView);
        }
    }
}

@Override
public void onPageScrollStateChanged(int state) {
}

private void handleComments(MomentPojo moment) {
    final int comments = Integer.parseInt(moment.getCommentsNumber());
    if (comments > 0) {
        mTvNumberOfComments.setText(Utility.showNumInNumK(comments));
    } else {
        mTvNumberOfComments.setText("");
    }
}

private void handleLikeState(MomentPojo moment) {
    if (moment.wasLiked()) {
        mBtnLike.setImageResource(R.drawable.ic_favorite_clicked);
    } else {
        mBtnLike.setImageResource(R.drawable.ic_favorite_unclicked);
    }

    final int likes = Integer.parseInt(moment.getLikesNumber());
    if (likes > 0) {
        mTvNumberOfLikes.setText(Utility.showNumInNumK(likes));
    } else {
        mTvNumberOfLikes.setText("");
    }
}

// MARK: OnClick and OnClick actions

@Override
public void onClick(View v) {
    final MomentPojo moment = mMoments.get(mSelectedIndex);
    if (v == mBtnComments || v == mTvNumberOfComments) {
        actionComment(mMoments.get(mSelectedIndex).getID());
    } else if (v == mBtnLike || v == mTvNumberOfLikes) {
        actionLike(moment);
    } else if (v == mBtnShare || v == mTvNumberOfShares) {
        actionShare();
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent result) {
    mCreativeHandler.onActivityResult(requestCode, resultCode, result);
    if (resultCode == RESULT_OK) {
        switch (requestCode) {
            case Crop.REQUEST_PICK:
                beginCrop(result.getData());
                break;

            case Crop.REQUEST_CROP:
                handleEdit(resultCode, result, cropFileUri);
                break;
        }

    }
    super.onActivityResult(requestCode, resultCode, result);
}

private void actionShare() {
    MomentPojo momentPojo = mMoments.get(mVp.getCurrentItem());
    MomentOptions.actionShare(this, momentPojo);
}

private void actionComment(String momentID) {
    ProgressBarClass.startLoading(this);
    new TimelineCommentsGetRequest(momentID, this);
}

private void actionLike(MomentPojo moment) {
    new LinkerLikePostRequest(LinkerPojo.KEY_SOURCE_TYPE_MOMENT, moment.getID(), new LinkerLikePostRequest.Callback() {
        @Override
        public void onErrorResult(String err) {
            // TODO: handle error
        }
    });
    Utility.d("like state: " + moment.wasLiked());
    final int likes = Integer.parseInt(moment.getLikesNumber());
    if (moment.wasLiked()) {
        moment.setWasLiked(false);
        moment.setLikesNumber((likes - 1) + "");
        mBtnLike.setImageResource(R.drawable.ic_favorite_unclicked);
    } else {
        moment.setWasLiked(true);
        moment.setLikesNumber((likes + 1) + "");
        mBtnLike.setImageResource(R.drawable.ic_favorite_clicked);
    }
    handleLikeState(moment);

    if (mShouldSaveToDB) {
        MomentDB momentDB = mMomentsDB.get(mSelectedIndex);
        if (momentDB.wasLiked()) {
            momentDB.setWasLiked(false);
            momentDB.setLikesNumber((likes - 1) + "");
        } else {
            momentDB.setWasLiked(true);
            momentDB.setLikesNumber((likes + 1) + "");
        }
        momentDB.save();
    }

    mMoments.set(mSelectedIndex, moment);
    AppInstance.sharedInstance().getBus().post(new TimelineBusMomentChanged(moment, TimelineBusMomentChanged.KEY_STATE_LIKED));

}

@Override
public void onFinishedImageEditing(Uri outputFilePath) {
    handleEdit(RESULT_OK, null, outputFilePath);
}

// MARK: Comments
@Override
public void onMomentResult(ArrayList<CommentPojo> comments) {
    final LinkerPojo pojo = new LinkerPojo(mMoments.get(mSelectedIndex));
    ProgressBarClass.dismissLoading();
    CommentsActivity.setInstance(this, pojo, comments);
}

@Override
public void onErrorResult(String err) {
    ProgressBarClass.dismissLoading();
    MyToast.makeText(getString(R.string.gen_Something_went_wrong), MyToast.KEY_TYPE_RED).show();
}

// MARK: Settings

private class SettingsDialog implements ImageRotatePutRequest.Callback {

    private MomentDB mMomentDB;
    private ArrayList<String> mOptions;

    public SettingsDialog(MomentDB momentDB) {
        this.mMomentDB = momentDB;

        final String type = momentDB.getType();
        setOptions(type);
        createDialog();
    }

    private void setOptions(String type) {
        mOptions = new ArrayList<>();
        switch (type) {
            case TimelineUtils.KEY_TYPE_IMAGE:
                mOptions.add(getString(R.string.rotate_left));
                mOptions.add(getString(R.string.rotate_right));
                //mOptions.add(getString(R.string.timeline_moment_crop));
                mOptions.add(getString(R.string.timeline_moment_edit));
                break;

            case TimelineUtils.KEY_TYPE_TEXT:
                break;

            case TimelineUtils.KEY_TYPE_LINK:
                break;

            case TimelineUtils.KEY_TYPE_VIDEO:
                break;
        }
        mOptions.add(getString(R.string.gen_Delete));
    }

    private void createDialog() {
        final ListViewDialog dialog = new ListViewDialog(TimelineMomentActivity.this);
        dialog.setOnItemClickListener(mOptions, new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int i, long id) {
                final String option = mOptions.get(i);

                if (option.equals(getString(R.string.gen_Delete))) {
                    actionDelete();
                } else if (option.equals(getString(R.string.rotate_left))) {
                    actionRotate(false);
                } else if (option.equals(getString(R.string.rotate_right))) {
                    actionRotate(true);
                } /*else if (option.equals(getString(R.string.timeline_moment_crop))) {
                    actionCrop();
                }*/ else if (option.equals(getString(R.string.timeline_moment_edit))) {
                    actionEdit();
                }
                dialog.dismiss();
            }
        });
        dialog.show();
    }

    private void actionEdit() {

        File bitmapFile = mAdapter.getBitmap();
        if (bitmapFile != null) {
            mCreativeHandler.startFeather(Uri.fromFile(bitmapFile));
        }


        //final MomentPojo momentPojo = mMoments.get(mVp.getCurrentItem());
        //final String picUrl = Utility.getImageBySize(momentPojo.getContent(), MediaUtils.SIZE_MEDIUM, MediaUtils.SIZE_ORIGINAL);
        //Uri picUri = Uri.parse(picUrl);
        //mCreativeHandler.startFeather(picUri);
        //File imageFile = DBManager.getImageFile(TimelineMomentActivity.this, momentPojo.toMomentDB(mStoryDB));=
    }

    private void actionDelete() {
        MomentPojo currentMomentPojo = mMoments.get(mVp.getCurrentItem());
        MomentOptions.actionDeleteMoment(TimelineMomentActivity.this, currentMomentPojo, mMoments.size(), mStory.getID());
        finish();
    }

    private void actionRotate(boolean isClockWise) {
        MomentPojo momentPojo = mMoments.get(mVp.getCurrentItem());

        new ImageRotatePutRequest(momentPojo.getID(), isClockWise, this);

        float currentRotation = Float.parseFloat(mMomentDB.getRotation());
        if (isClockWise) {
            currentRotation += 90;
        } else {
            currentRotation -= 90;
        }

        if (mShouldSaveToDB) {
            mMomentDB.setRotation(currentRotation + "");
            mMomentDB.save();
            momentPojo = mMomentDB.converter();
        }

        momentPojo.setRotation(currentRotation + "");
        mMoments.set(mSelectedIndex, momentPojo);
        setViewPager();

        AppInstance.sharedInstance().getBus().post(new TimelineBusMomentChanged(momentPojo, TimelineBusMomentChanged.KEY_STATE_ROTATE));
    }

    @Override
    public void onImageRotateResult() {
        Utility.d("image rotated ");
    }

    @Override
    public void onErrorResult(String err) {}

}

@Override
protected void onDestroy() {
    AppInstance.sharedInstance().getBus().unregister(this);
    super.onDestroy();
}
….
// MARK: Crop

private void beginCrop(Uri source) {
    Crop.of(source, cropFileUri).asSquare().start(this);
}
…..
}

Adapter:

public class TimelineMomentPagerAdapter extends PagerAdapter {
…
public TimelineMomentPagerAdapter(Context mContext, List<MomentPojo> mArray, StoryDB aStoryDB) {
    this.mContext = mContext;
    this.mArray = mArray;
    this.mStoryDB = aStoryDB;
}

public File getBitmap() {
    convertBitmapToFile();
    return mCurrentBitmapFile;
}

public void setBitmap(View aView) {
    ImageView imageView = (ImageView) aView.findViewById(R.id.mIvVpContent);
    if (imageView != null) {
        mCurrentImageViewBitmap = getBitmap(imageView);
    }
}

private void convertBitmapToFile() {
    /*View currentPagerView = mVp.getChildAt(mVp.getCurrentItem());
    ImageView contentView = (ImageView) currentPagerView.findViewById(R.id.mIvVpContent);
    Bitmap bitmap = getBitmap(contentView);*/

    final File bitmapFolder = new File(mContext.getCacheDir(), "bitmap");
    if (!bitmapFolder.exists()) {
        bitmapFolder.mkdir();
    }

    mCurrentBitmapFile = new File(bitmapFolder, "currentBitmap");

    try {
        if (mCurrentBitmapFile.exists()) {
            mCurrentBitmapFile.delete();
        }

        mCurrentBitmapFile.createNewFile();
        FileOutputStream stream = new FileOutputStream(mCurrentBitmapFile);

        if (mCurrentImageViewBitmap != null) {
            mCurrentImageViewBitmap.compress(Bitmap.CompressFormat.JPEG, 75, stream);
        }

        stream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override
public int getCount() {
    return mArray.size();
}

@Override
public boolean isViewFromObject(View view, Object object) {
    return view == object;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((RelativeLayout) object);
}

@Override
public Object instantiateItem(ViewGroup container, final int position) {

    final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    final View v = inflater.inflate(R.layout.timeline_moment_viewpager, container, false);
    final MomentPojo momentPojo = mArray.get(position);

    mIvContent = (ImageView) v.findViewById(R.id.mIvVpContent);
    mTvContent = (TextView) v.findViewById(R.id.mTvVpContent);
    mIvPlay = (ImageView) v.findViewById(R.id.mIvPlay);
    mPbProgressBar = (ProgressBar) v.findViewById(R.id.pbProgress);

    final String type = momentPojo.getType();
    final String content = momentPojo.getContent();

    switch (type) {
        case TimelineUtils.KEY_TYPE_IMAGE: //---------------------------------------------------IMAGE
            mIvPlay.setVisibility(View.GONE);
            mIvContent.setVisibility(View.VISIBLE);
            mTvContent.setVisibility(View.GONE);

            final String contentHigherQuality = momentPojo.getContentHigherQuality();
            final String newContent;
            if (JavaUtils.isNotNullNotEmptyNotWhiteSpaceOnly(contentHigherQuality)) {
                newContent = contentHigherQuality;
            } else if (JavaUtils.isNotNullNotEmptyNotWhiteSpaceOnly(content)) {
                newContent = content;
            } else {
                newContent = momentPojo.getLocalPath();
            }

            mPbProgressBar.setVisibility(View.VISIBLE);
            Glide.with(BaseApplication.getInstance()).load(newContent).asBitmap().placeholder(R.drawable.ic_action_picture).into(new SimpleTarget<Bitmap>() {
                @Override
                public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation) {
                    if (bitmap != null) {
                        mIvContent.setImageBitmap(bitmap);
                    }
                    mPbProgressBar.setVisibility(View.INVISIBLE);
                }

                @Override
                public void onLoadFailed(final Exception e, final Drawable errorDrawable) {
                    mPbProgressBar.setVisibility(View.INVISIBLE);
                }
            });

            setImageRotation(momentPojo.getRotation());
            if (position == 0 && !mWasCurrentImageBitmapInitialized) {
                mCurrentImageViewBitmap = getBitmap(mIvContent);
                mWasCurrentImageBitmapInitialized = true;
            }
            break;
        case TimelineUtils.KEY_TYPE_TEXT:  //---------------------------------------------------TEXT
        case TimelineUtils.KEY_TYPE_LINK:  //---------------------------------------------------LINK
            ….
            break;
        case TimelineUtils.KEY_TYPE_AUDIO: //---------------------------------------------------AUDIO
        case TimelineUtils.KEY_TYPE_VIDEO: //---------------------------------------------------VIDEO
            …
            break;

        case TimelineUtils.KEY_TYPE_PDF: //-----------------------------------------------------PDF
            ….
            break;

        case TimelineUtils.KEY_TYPE_YOUTUBE: //---------------------------------------------------VIDEO
           ….
            break;

    }

    container.addView(v);
    return v;
}
….

public Bitmap getBitmap(ImageView aImageView) {
    Bitmap image = null;
    if (aImageView == null) return null;
    Drawable drawable = aImageView.getDrawable();
    if (drawable != null) {
        if (drawable instanceof GlideBitmapDrawable) {
            GlideBitmapDrawable bitmapDrawable = (GlideBitmapDrawable) aImageView.getDrawable();
            image = bitmapDrawable.getBitmap();
        } else if (drawable instanceof BitmapDrawable) {

            BitmapDrawable bitmapDrawable = (BitmapDrawable) aImageView.getDrawable();
            image = bitmapDrawable.getBitmap();
        }
    }
    return image;
}
….
}

This code works but not always, there are cases in which currentView is null after passing this method. After some debugging session I figured out that while onPageSelected gives me the real index that can be for example 10 the view pager holds it's view always in the 0-2 positions. so, on swiping all three item are swapped but they remain in their 0-2 positions.

How can I achieve my task?

Upvotes: 2

Views: 581

Answers (1)

kris larson
kris larson

Reputation: 30985

First, get rid of all the code in the OnPageChangeListener that modifies something in the adapter.

Add a map of bitmaps to the adapter:

private Map<Integer, Bitmap> mBitmapMap;
private Map<Integer, View> mViewMap;

In instantiateItem() after inflation:

mViewMap.put(position, v);

In your callback onResourceReady():

mBitmap.put(position, bitmap); // position is final

In destroyItem():

mBitmapMap.put(position, null);  // remove from map
mViewMap.put(position, null);

Then implement new methods:

public Bitmap getBitmapAt(int position) {
    return mBitmapMap.get(position);
}

public View getViewAt(position) {
    return mViewMap.get(position);
}

Call from activity:

bitmap = mAdapter.getBitmapAt(mVp.getCurrentItem());
view = mAdapter.getViewAt(mVp.getCurrentItem());

Now you can leave the offscreen page limit at its default.

Upvotes: 2

Related Questions