package expo.modules.kotlin.views import android.content.Context import android.graphics.Canvas import android.widget.LinearLayout import androidx.annotation.UiThread import com.facebook.react.uimanager.BackgroundStyleApplicator import com.facebook.react.uimanager.StateWrapper import expo.modules.kotlin.AppContext /** * A base class that should be used by every exported views. */ abstract class ExpoView( context: Context, val appContext: AppContext ) : LinearLayout(context) { var stateWrapper: StateWrapper? = null val shadowNodeProxy: ShadowNodeProxy = ShadowNodeProxy(this) /** * If set to `true`, the view utilizes the Android layout system rather than React Native's. * This simulates rendering the native view by Android outside of React Native's view hierarchy, * with parent dimensions enforced by Yoga. * * Setting it to `true` does not guarantee that the layout calculated by Android will be accurate. * In some situations, the content may render outside the bounds defined by Yoga. * * However, without this setting, React Native will not re-render your view when [requestLayout] is triggered. * Read more: [React Native issue #17968](https://github.com/facebook/react-native/issues/17968) */ open val shouldUseAndroidLayout: Boolean = false /** * Manually trigger measure and layout. * If [shouldUseAndroidLayout] is set to `true`, this method will be called automatically after [requestLayout]. */ @UiThread fun measureAndLayout() { measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) ) layout(left, top, right, bottom) } override fun requestLayout() { super.requestLayout() if (shouldUseAndroidLayout) { // We need to force measure and layout, because React Native doesn't do it for us. post { measureAndLayout() } } } open fun clipToPaddingBox(canvas: Canvas) { // When the border radius is set, we need to clip the content to the padding box. // This is because the border radius is applied to the background drawable, not the view itself. // It is the same behavior as in React Native. if (!clipToPadding) { return } BackgroundStyleApplicator.clipToPaddingBox(this, canvas) } override fun dispatchDraw(canvas: Canvas) { clipToPaddingBox(canvas) super.dispatchDraw(canvas) } }