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
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
CodePudding user response:
The first issue with your code is that you styling it with 200x200 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.
CodePudding user response:
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)
}
}