skip to Main Content

I am trying to integrate camera-x inside an android fragment in react-native

Here is my native code

class CealScanQrView(context: Context): FrameLayout(context) {

 init {
        val frameLayoutParams = ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT
        )
        layoutParams = frameLayoutParams
       setLayoutParams(layoutParams)
        setBackgroundColor(Color.parseColor("#5FD3F3"))

        preview = PreviewView(context)
        preview.id = View.generateViewId()
        preview.layoutParams = ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT
        )
        addView(preview)
}
//other non related code
......
}

Instead of Framelayout, I tried using Linearlayout and ConstraintLayout as well but same issue persists

on react-native side, I am using it as follows

const App = () => {
//non-related code here
.....

 return (
    <SafeAreaView>
      <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />

      {isCameraPermissionGranted ? (
        <CealScanQrViewManager
          style={{
            // converts dpi to px, provide desired height
            height: PixelRatio.getPixelSizeForLayoutSize(200),
            // converts dpi to px, provide desired width
            width: PixelRatio.getPixelSizeForLayoutSize(200),
          }}
          ref={ref}
          onChange={readQr}
        />
      ) : (
        <View style={{backgroundColor: 'red'}} />
      )}
      <Text style={{color: 'red', fontSize: 25}}>{firstText}</Text>
      <Text style={{color: 'red', fontSize: 25}}>{secondText}</Text>
    </SafeAreaView>
  );
} 

This is how my UI looks

enter image description here

You can see there is space between camera and the first text in red color.
that space is the Framelayout but the camera does not occupy the entire space of Framelayout which I don’t understand why

Full source code here

2

Answers


  1. Chosen as BEST ANSWER

    Pavlo's answer helped me but if anyone is interested in the exact answer, here is what I did

    I removed the style prop from native side and changed manuallyLayoutChildren method as follows

      private fun manuallyLayoutChildren(view: ViewGroup) {
            for (i in 0 until view.childCount) {
                val child = view.getChildAt(i)
                child.measure(
                    View.MeasureSpec.makeMeasureSpec(view.measuredWidth, View.MeasureSpec.EXACTLY),
                    View.MeasureSpec.makeMeasureSpec(view.measuredHeight, View.MeasureSpec.EXACTLY))
                child.layout(0, 0, child.measuredWidth, child.measuredHeight)
            }
    
        }
    

  2. The first issue with your code is that you styling it with 200×200 pixels here:

    <CealScanQrViewManager
              style={{
                // You intentionally scale it to be small
                height: PixelRatio.getPixelSizeForLayoutSize(200),
                width: PixelRatio.getPixelSizeForLayoutSize(200),
              }}
    

    The second thing is that you are using PreviewView from androidx camera package, which is not a simple SurfaceView or TextureView but rather a wrapper over either. What does it mean – the documentation states that

    It internally uses either a TextureView or SurfaceView to display the camera feed, and applies required transformations on them to correctly display the preview, this involves correcting their aspect ratio, scale and rotation.

    That means that if will use only the correct view disregarding any warping related to the size of the preview container as it was before with Surface o Texture views. So if the preview size or aspect ratio is different from your screen(or component which parents your preview), it won’t match the parent dimensions but will be scaled to look ‘correctly’ and inside the preview size bounds.

    Channeling the camera preview inside the plain Surface or Texture views won’t have this limitation, but it will be warped if the dimensions or aspect ration of your container and preview won’t match.

    It is not the solution, but there is no simple solution in your case – you have to consider the info above to adjust your code.

    Edit

    There is one more method, but it is tricky, and I won’t give you an implementation – just a general approach. What you can do it that you can get the aspect ratio and size of your preview and cut it via negative padding or custom view container with some relevant logic in there. This is not the easy way, nor is it that hard – it is just tricky and seemingly very redundant.

    For example, if your preview aspect ratio (h/w) = 1.20 and your screen aspect ratio (h/w) = 1.40, your preview will have gaps at the top and bottom if centered. Now your goal is to make the aspect ratio of the preview to be 1.40 without warping the image rendered on it – you will have to cut the preview from left and right for it not to have gaps at the top and bottom. And vice versa if your preview aspect ratio is bigger than the screens one

    Something like that.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search