androidkotlinviewdrawingpinchzoom

How to acces to a View under a View


I'm a beginner in Android, I have a frameLayout which contains Draw view on top and ImageView (using PhotoView) on the back so I can draw on it.

I want to add a feature to my ImageView so I can zoom it move it left right so I used a thirdParty library (PhotoView) for that but the problem was that I cannot reach the Image cause my Draw view is on top of it, if I hide the Draw view the user Drawing will hide when resizing the image and I don't want that, I want it like instagram story's you can resize your story without hiding your drawing..

I found a solution and I find it weird or not that good or professional. I added duplicated ImageView (PhotoView library) in the framelayout on top of my Drawing view and I made it transparent, and I read the PhotoView library code and I attached the functions I need to the background ImageView so when I zoom the foreground image, the background will zoom with it and so fourth without hiding the drawing because it's transparent...

When I click on draw button the foreground ImageView will hide and I can keep drawing normally.

This is in MainActivity:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        b = ActivityMainBinding.inflate(layoutInflater)
        val view = b.root
        setContentView(view)

//imgtest forground transparent ImageView
//img Background ImageView
//b ViewBinding

attach()

b.DrawOrSize.setOnClickListener {
            if (b.imgtest.visibility == GONE) {
                b.imgtest.visibility = VISIBLE
                b.imgtest.text = "DRAW"
            } else {
                b.imgtest.visibility = GONE
                b.imgtest.text = "SIZE"
            }
        }
}
 fun attach() {

//attach imgtest(forground) movement to img(background)

         b.imgtest.attacher.maximumScale = 500f
         b.img.attacher.maximumScale = 500f
         b.imgtest.setOnScaleChangeListener { _, _, _ ->
             b.img.setScale(b.imgtest.scale, false) 

        }
        b.imgtest.setOnTouchListener { view, motionEvent ->
            b.img.attacher.onTouch(view, motionEvent)
        }
    }

My xml framelayout :

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:animateLayoutChanges="true"
    android:orientation="vertical"
    android:layout_gravity="center"
    android:gravity="center"
    tools:context="com.at.test.MainActivity">

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/strokedballe"
>

    <com.github.chrisbanes.photoview.PhotoView 
        //background image
        android:id="@+id/img"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="5dp"
        android:background="@android:color/transparent"
        android:src="@mipmap/untitled"

        />
    <com.at.test.Draw
        android:id="@+id/Draw"
        android:layout_margin="5dp
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    </com.at.test.Draw>

    <com.github.chrisbanes.photoview.PhotoView
        //Forground image
        android:id="@+id/imgtest"
        android:layout_width="match_parent"
        android:src="@android:color/transparent"
        android:layout_gravity="center"
        android:layout_marginTop="5dp"
        android:layout_height="match_parent" />
</FrameLayout>
.
.
.

My question is is there anyway to pass touchevents on view under a view especally in drawing case or should i stick with my sol?

And another questions as a beginner in Android should I use always documentation or should I remember the code I'm a little confused I know 80% of the basics(classes,functions,OOP...) but when it come to android like handling permissions,importing a file from storage,adding providers,exporting file from the app,and some of android functions i always forget how to do them , do programmers use documentation for all of this stuff or they save the code in notes for example I'm quite confused and I don't know my progress with this qts in my head, I hope I find an answer here, thank you


Solution

  • I found the solution ! Instead of using another transparent imageview and make the design more complex i figured out another way, its to change the onTouchEvent methode in the Draw class

    in my Draw class the function was :

        override fun onTouchEvent(event: MotionEvent?): Boolean {
    
        val x=event?.x
        val y =event?.y
    
        when(event?.action){
            MotionEvent.ACTION_DOWN -> {
               
                drawPaint!!.color=color
                drawPaint!!.strokeWidth=brushsize
    
                if (y != null && x != null) {
    
                    drawpath!!.moveTo(x,y)
                    drawpath!!.lineTo(x,y)
                    pathlist.add(drawpath!!)
                }
            }
          
            MotionEvent.ACTION_MOVE ->{
                if (y != null && x != null) {
                        drawpath!!.lineTo(x,y)}
                }
    
            }
            MotionEvent.ACTION_UP ->{
                if (y != null && x != null) {
                    drawpath=CustomPath(color,brushsize)
    
    
                }}
            else -> return false
        }
        invalidate()
        return true
    }
    

    the overriden funtion OnTouchEvent is necessary to draw and its called automatically when declaring the Draw view in the activity xml but it stops me from resizing or touching the background imageView so the solution was to avoid overriding it and create it as a normal function in the Draw class i just removed the override word and renamed the function to a custom name (onTouch for my case) now the function is not called automatically so i can manually control it in my main activity when i want to draw i call it and i cancel it when i want to access to the view under it (the background image to resize)

    in my main activity:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        b = ActivityMainBinding.inflate(layoutInflater)
        val view = b.root
        setContentView(view)
        //img Background ImageView
        //b ViewBinding
    
         setDrawOriSizeButton()
    
         }
         private fun setDrawOrSizeButton() {
    
        var canDraw=false //to verify if we are drawing or resizing
        b.DrawOrSize.setOnClickListener {
            if (canDraw==false){
                canDraw=true/*Drawing enabled resize disabled cannot access to the under View*/
                b.Draw.setOnTouchListener { view, motionEvent ->
                    b.Draw.onTouch(motionEvent)} //calling the touch methode
    
            }else {
                b.Draw.setOnTouchListener(null) //canceling touch methode
                canDraw=false//drawing disabled resize enabled accesing to the under view possible
            }
    
    
        }
    }
    

    }

    Dont forget to add in the DrawVieww on xml or it will not work !

            android:clickable="false"
            android:focusableInTouchMode="false"
            android:focusable="false"
    

    Important: if you only add those lines to View in xml layout, it will not work u cant access the under View if the onTouchEvent methode for the forground View is working and in case of Draw view it will keep drawing even with those lines :)