Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there any sample code about cross activities from recyclerview to viewpager? #91

Open
xanahopper opened this issue Oct 6, 2017 · 7 comments
Labels

Comments

@xanahopper
Copy link

Recently I try to implement a cross activities demo. But I found that the ToActivity will flash at the moment it finished().
I use a SimpleTracker to generate ViewTransitionAnimator like:

GestureTransitions.from(fromRecyclerView, fromTracker).into(viewPager, pagerTracker)

only different is that fromRecyclerView is in FromActivity and viewPager in ToActivity.

I try to hide/show origin ImageView like your sample code but pageAdapter.getViewHolder always return null. I don't know how to do it.

@alexvasilkov
Copy link
Owner

It's really hard to help if you don't provide your code. Please share related code pieces and describe your problems with it.

It seems like you just need to hide everything on last animation step (isLeaving && pos == 0)

@MichaelJokAr
Copy link

I have the same question, need sample too

@xanahopper
Copy link
Author

xanahopper commented Oct 12, 2017

I try to write a simple demo here. The problem is when ToActivity exit it will have a flash. I tried debug and slow down animation but don't see any thing so I suspect the original image showed after ToActivity disappear so it will see a empty place and show ImageView immediately after that. The result is a flash.

  • activity_from.xml
<CoordinatorLayout>
    <AppBarLayout>
        <Toolbar />
    </AppBarLayout>
    <RecyclerView android:id="@+id/recycler_view" />
</CoordinatorLayout>
  • FromActivity.java
class FromActivity extend AppCompatActivity {
    private mRecyclerView: RecyclerView;
    private mAdapter: PhotoAdapter;
    
    public override void onCreate(/*...*/) {
        mRecyclerView = findViewById(R.id.recycler_view);
        mRecyclerView.setLayoutManager(new GridLayoutManager(/*...*/));
        mAdapter = new PhotoAdapter();
        mRecyclerView.setAdapter(mAdapter);
    }

    @Subscribe
    void onImageShowEvent(ImageShowEvent event) {
        if (event.adapterPosition < photo.getSize()) {
            StatusViewHolder holder = (StatusViewHolder)mRecyclerView.findViewHolderForAdapterPosition(event.adapterPosition)
            holder.statusImage.setVisibility(event.show ? View.VISIBLE : View.INVISIBLE)
        }
    }
}
  • activity_to.xml
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/photo_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent">

    <View
        android:id="@+id/photo_background"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/black"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/photo_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent">

    </android.support.v4.view.ViewPager>

    <FrameLayout
        android:id="@+id/status_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:fitsSystemWindows="true"
        android:background="#80000000">

        <TextView
            android:id="@+id/photo_status"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:textSize="10sp"
            android:textColor="?android:attr/textColorPrimaryInverse"/>
    </FrameLayout>
</FrameLayout>
  • item_photo_full.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent">

    <com.alexvasilkov.gestures.views.GestureImageView
        android:id="@+id/photo_full_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</FrameLayout>
  • PhotoAdapter.kt
class PhotoDetailPagerAdapter(val viewPager: ViewPager,
                              val photoList: List<Status>,
                              val photoInfos: List<ImageInfo>,
                              val thumbnailUri: Uri?,
                              val actionDelegate: ActionDelegate) : RecyclePagerAdapter<PhotoDetailPagerAdapter.ViewHolder>() {

    // PLEASE ignore the different constructor parameters in FromActivity.java
    private var firstView = true
    private val context = viewPager.context
    var activated = true
        set(value) {
            if (field != value) {
                field = value
                notifyDataSetChanged()
            }
        }

    override fun onCreateViewHolder(container: ViewGroup): ViewHolder {
        val holder = ViewHolder(container)

        holder.image.controller.settings
                .setMaxZoom(10f)
                .setDoubleTapZoom(3f)
                .setDoubleTapEnabled(true)
                .setFitMethod(Settings.Fit.INSIDE)
                .setZoomEnabled(true)
                .setExitEnabled(true)
                .setFillViewport(true)
                .setGravity(Gravity.CENTER)
                .setPanEnabled(true)

        holder.image.controller.setLongPressEnabled(true)
        holder.image.controller.enableScrollInViewPager(viewPager)
        return holder
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val photoInfo = photoInfos[position]
        loadImage(photoInfo, holder.image)
        holder.image.controller.setOnGesturesListener(object : GestureController.OnGestureListener {
            override fun onSingleTapUp(event: MotionEvent): Boolean = false

            override fun onDown(event: MotionEvent) {

            }

            override fun onDoubleTap(event: MotionEvent): Boolean = false

            override fun onUpOrCancel(event: MotionEvent) {}

            override fun onLongPress(event: MotionEvent) {
                actionDelegate.onLongClick(holder, photoList[position], photoInfo)
            }

            override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
                actionDelegate.onClick()
                return true
            }

        })
    }

    override fun onRecycleViewHolder(holder: ViewHolder) {
        super.onRecycleViewHolder(holder)

        Glide.clear(holder.image)
        holder.image.setImageDrawable(null)
    }

    override fun getCount(): Int = if (!activated) 0 else photoList.size

    private fun loadImage(info: ImageInfo, imageView: GestureImageView) {
        if (firstView && thumbnailUri != null) {
            Image.loadImage(context, thumbnailUri, imageView, false)
        }
        firstView = false
        if (info.height / info.width > Image.LARGE_SCREEN_RATIO) {
            imageView.controller.settings
                    .setFitMethod(Settings.Fit.HORIZONTAL).gravity = Gravity.TOP
        } else {
            imageView.controller.settings
                    .setFitMethod(Settings.Fit.INSIDE).gravity = Gravity.CENTER
        }
        val gif = info.imageUri?.let { Image.getMimeType(info.imageUri) == "image/gif" } ?: false
        when (info.cacheState) {
            ImageInfo.CACHE_NONE,
            ImageInfo.CACHE_THUMBNAIL -> {
                val large = (info.height / info.width > Image.LARGE_SCREEN_RATIO)
                val param = Image.getLoadParameter(imageView, info.imageUri!!, large, false)
                Image.loadImage(context, Uri.parse(info.imageUri.toString() + param), imageView, false, false)
            }
            ImageInfo.CACHE_LARGE -> {
                val param = Image.getLoadParameter(imageView, info.imageUri!!, false, true, 576)
                Image.loadImage(context, Uri.parse(info.imageUri.toString() + param), imageView, false, gif)
            }
            ImageInfo.CACHE_ORIGIN -> {
                Image.loadImage(context, info.imageUri!!, imageView, false, gif)
            }
        }
    }

    override fun destroyItem(container: ViewGroup?, position: Int, `object`: Any?) {
        super.destroyItem(container, position, `object`)
    }

    inner class ViewHolder(parent: ViewGroup) : RecyclePagerAdapter.ViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_photo_full, parent, false)) {
        val image: GestureImageView by lazy { itemView.findViewById<GestureImageView>(R.id.photo_full_image) }
    }

    interface ActionDelegate {
        fun onClick()

        fun onLongClick(holder: ViewHolder, status: Status, item: ImageInfo): Boolean
    }
}
  • ToActivity.kt
class PhotoDetailActivity : AppCompatActivity,
        ViewPositionAnimator.PositionUpdateListener, 
        PhotoDetailPagerAdapter.ActionDelegate {

    private val viewPager: ViewPager by lazy { findViewById<ViewPager>(R.id.photo_pager) }
    private val pagerAdapter by lazy { PhotoDetailPagerAdapter(viewPager, photoList, photoInfos, thumbnailUri, this) }
    private val pagerTracker: SimpleTracker by lazy {
        object : SimpleTracker() {
            override fun getViewAt(position: Int): View? = pagerAdapter.getViewHolder(position)?.image
        }
    }

    private val animator: ViewsTransitionAnimator<Int> by lazy {
        GestureTransitions.from(fromRecyclerView?.get()!!, fromTracker!!).into(viewPager, pagerTracker)
    }

    private val statusText by lazy { findViewById<TextView>(R.id.photo_status) }
    private val statusLayout by lazy { findViewById<FrameLayout>(R.id.status_layout) }
    private val background: View by lazy { findViewById<View>(R.id.photo_background) }
    private var position = 0
    private var hideOrigImage = false
    private var fromPosition: Int = -1
    private var currentPosition: Int = 0

    override val isCommonTheme: Boolean
        get() = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_photo_detail)

        if (savedInstanceState != null) {
            position = savedInstanceState.getInt("POSITION", 0)
        }
        fromPosition = intent.getIntExtra(EXTRA_POSITION, -1)
        animator.enter(position, savedInstanceState == null)

        initPager()
        initAnimator()
    }

    private fun initPager() {
        viewPager.adapter = pagerAdapter
        pagerAdapter.activated = true
        viewPager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
            override fun onPageSelected(position: Int) {
                onPhotoInPagerSelected(position)
            }
        })
        onPhotoInPagerSelected(0)
    }

    private fun initAnimator() {
        animator.addPositionUpdateListener(this)
    }

    private fun onPhotoInPagerSelected(position: Int) {
        currentPosition = position

        val status = photoList[position]
        val html = String.cleanTag(status.text)
        statusText.text = html

//  HERE: I tried to hide origin ImageView in another activity like your sample but failed.

//        val image = pagerAdapter.getViewHolder(currentPosition).image
//        image.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
//            override fun onPreDraw(): Boolean {
//                if (hideOrigImage) {
//                    image.viewTreeObserver.removeOnPreDrawListener(this)
//                    EventBus.getDefault().post(ImageShowEvent(fromPosition, false))
//                } else if (image.drawable != null) {
//                    hideOrigImage = true
//                }
//                return true
//            }
//        })
    }

    override fun onPositionUpdate(position: Float, isLeaving: Boolean) {
        background.setVisibility(position != 0f, false)
        background.background.alpha = (255 * position).toInt()

        statusLayout.setVisibility(position == 1f, false)
        statusLayout.background.alpha = (255 * position).toInt()

        if (isLeaving && position == 0f) {
            EventBus.getDefault().post(ImageShowEvent(fromPosition, true))
            val image = pagerAdapter.getViewHolder(currentPosition).image
            image.controller.settings.disableBounds()
            image.positionAnimator.setState(0f, false, false)
            finish()
            overridePendingTransition(0, 0)
        }
    }

    override fun onBackPressed() {
        if (!animator.isLeaving) {
            animator.exit(true)
        } else {
            animator.exit(false)
            finish()
            overridePendingTransition(0, 0)
        }
    }

    override fun onClick() {
        onBackPressed()
    }

    override fun onLongClick(holder: PhotoDetailPagerAdapter.ViewHolder, status: Status, item: ImageInfo): Boolean {
        val dialog = BottomSheetDialog(this)
        dialog.setTitle("Photo Actions")
        dialog.show()
        return true
    }

    companion object {
        val photoList = mutableListOf<Status>()
        val photoInfos = mutableListOf<ImageInfo>()
        val sourceRect = mutableListOf<Rect>()
        var thumbnailUri: Uri? = null
        var fromRecyclerView: WeakReference<RecyclerView>? = null
        var fromTracker: SimpleTracker? = null

        const val EXTRA_POSITION = "position"

        fun reset() {
            photoList.clear()
            photoInfos.clear()
            sourceRect.clear()
        }

        private fun setPhotoList(statusList: List<Status>, infoList: List<ImageInfo>) {
            reset()
            if (statusList.any { it.photo == null }) return
            photoList.addAll(statusList)
            photoInfos.addAll(infoList.map { it.copy(cacheState = ImageInfo.CACHE_ORIGIN) })
            thumbnailUri = Uri.parse(infoList[0].imageUri?.toString() + "@200w_1l.jpg")
        }

        fun open(from: Activity, recyclerView: RecyclerView, tracker: SimpleTracker, position: Int,
                 statusList: List<Status>, infoList: List<ImageInfo>) {
            val intent = Intent(from, PhotoDetailActivity::class.java)
            intent.putExtra(EXTRA_POSITION, position)

            fromRecyclerView = WeakReference(recyclerView)
            fromTracker = tracker
            setPhotoList(statusList, infoList)

            from.startActivity(intent)
            from.overridePendingTransition(0, 0)
        }
    }
}

That all most the entire demo.

@Aidenat9
Copy link

Aidenat9 commented Mar 1, 2019

I also expect the answer,thanks

@xanahopper
Copy link
Author

I have already solved this problem and maybe pack and post it later. The main focus of solution is to write your own FromRecyclerViewListener extend from an internal class FromBaseListener.

@malikthebest
Copy link

I have already solved this problem and maybe pack and post it later. The main focus of solution is to write your own FromRecyclerViewListener extend from an internal class FromBaseListener.

Can you share the solution with us please?

@janjandev
Copy link

@malikthebest Cross-activity from recyclerview to viewpager, this problem solved?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants