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

Add responsive layout #116

Open
jlucas577 opened this issue Feb 11, 2021 · 2 comments
Open

Add responsive layout #116

jlucas577 opened this issue Feb 11, 2021 · 2 comments

Comments

@jlucas577
Copy link

Hello guys! I opened this pr to get help on a possible responsiveness of the library, my problem is that when I position the view on a particular float, on larger screens it is excellent and working very well, however on smaller screens it just stops being "responsive" and the view ends up being on top of others that it shouldn't ..

I've tried to set the screen percentage as a top margin for example, but the problem still persists, and the funniest thing is that it only happens on screens smaller than 5 inches.

Prinscreen
Prinscreen

@Albul
Copy link

Albul commented Feb 11, 2021

@jlucas577 First of all you need to fix your layout on a small screens.
Second you need to redesign overlay view, and put title and description of your tutorial at the very top. Or when ui component is at the top of the screen you need to readjust title and description to the bottom.
Check example from my app:

private fun initOverlayView(
        rootView: View,
        targetView: View,
        activity: RootActivity,
    ) {
       val overlay: View = activity.layoutInflater
            .inflate(R.layout.block_tutorial_feature, rootView, false)

        val targetWidth: Float = targetView.width.toFloat()
        val targetHeight: Float = targetView.height.toFloat()
        val targetMinSize: Float = min(targetWidth, targetHeight)
        val targetMaxSize: Float = max(targetWidth, targetHeight)
        val location = IntArray(2)
        targetView.getLocationInWindow(location)
        // This is coords on window. It is hard to say where is start point.
        // But it seems that in split screen mode without status bar,
        // but without split screen mode it includes status bar
        val targetLeft: Float = location[0].toFloat()
        val targetTop: Float = location[1].toFloat()
        val targetRight: Float = targetLeft + targetView.width
        val targetBottom: Float = targetTop + targetView.height
        val targetCenterX: Float = targetLeft + targetWidth * 0.5f
        val targetCenterY: Float = targetTop + targetHeight * 0.5f

        val horizontalPadding: Int = activity.calcTutTextHorizPadding(rootView)

        val isInMultiWindowMode: Boolean =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) activity.isInMultiWindowMode else false

        overlay.findViewById<View>(R.id.tutorial_container).let {
            it.setOnTouchListener { v, event ->
                val eventX = if (isInMultiWindowMode) event.x else event.rawX
                val eventY = if (isInMultiWindowMode) event.y else event.rawY

                if (eventX in targetLeft..targetRight
                    && eventY in targetTop..targetBottom
                    && isTargetClickable
                ) {
                    false // Pass event under the hole
                } else {
                    true // Consume event
                }
            }
        }

        val titleField = overlay.findViewById<TextView>(R.id.tutorial_title_field).also {
            it.updatePadding(left = horizontalPadding, right = horizontalPadding)

            if (title.isNullOrEmpty()) {
                it.visibility = View.GONE
            } else {
                it.text = title
            }
        }

        val descriptionField = overlay.findViewById<TextView>(R.id.tutorial_description_field).also {
            it.updatePadding(left = horizontalPadding, right = horizontalPadding)

            if (description.isNullOrEmpty()) {
                it.visibility = View.GONE
            } else {
                it.text = description
            }
        }

        val okButton = overlay.findViewById<MaterialButton>(R.id.tutorial_ok_button).also {
            if (hasOk) {
                it.setOnClickListener {
                    finish(activity)
                }
            } else {
                it.visibility = View.GONE
            }
        }

        overlay.findViewById<View>(R.id.tutorial_try_button).visibility = View.GONE

        overlay.findViewById<ViewGroup>(R.id.tutorial_content_container).let { container ->
            if (isContentTransparent) {
                container.setBackgroundColor(ColorsAcore.transparent)
            }

            titleField.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
            descriptionField.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
            iconView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)

            container.updateLayoutParams<RelativeLayout.LayoutParams> {
                // Status bar as margin between hole and content
                val contentMargin: Int = activity.getDimensionPixelSize(R.dimen.tutorial_content_vert_margin)
                // In multiwindow mode status bar not counted as window size
                val statusBarHeight: Int = if (isInMultiWindowMode) 0 else activity.statusBarHeight
                val contentHeight = titleField.measuredHeight + descriptionField.measuredHeight +
                    iconView.measuredHeight + contentMargin

                val windowHeight: Int = activity.windowHeightNoSysBars

                val topRestHeight: Float = targetTop - statusBarHeight
                val bottomRestHeight: Float = windowHeight - targetBottom

                when {
                    // If top and bottom rest smaller than content
                    topRestHeight < contentHeight
                        && bottomRestHeight < contentHeight -> {
                        if (!isContentTransparent) {
                            container.setBackgroundColor(ColorsApp.tutorialBgColor)
                        }
                        adjustOkButtonColor(okButton, targetBottom)
                    }

                    // Top rest much bigger than bottom one. Show content above hole
                    topRestHeight > bottomRestHeight * 1.3f -> {
                        this.bottomMargin = windowHeight - (targetTop.toInt() - statusBarHeight) + contentMargin
                        adjustOkButtonColor(okButton, targetBottom)
                    }

                    // Default, show content below the hole
                    else -> {
                        this.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE)
                        this.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM)
                        // It is safe to set targetBottom as a topMargin, so there should be an extra margin
                        // between hole and top edge of the content which equals to notification bar height
                        this.topMargin = targetBottom.toInt() - statusBarHeight + contentMargin
                        this.bottomMargin = 0 // Or it will hide part of big content block
                    }
                }

            }
        }
    }

@Albul
Copy link

Albul commented Feb 11, 2021

@jlucas577 Also when you have components inside ScrollView which you want to highlight. First you need to scroll ScrollView to ensure targetView is visible on a small screen.

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

No branches or pull requests

2 participants