@ReactPropGroup(names = { ViewProps.BORDER_RADIUS, ViewProps.BORDER_TOP_LEFT_RADIUS, ViewProps.BORDER_TOP_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_LEFT_RADIUS }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderRadius(ReactImageView view, int index, float borderRadius) { if (!YogaConstants.isUndefined(borderRadius)) { borderRadius = PixelUtil.toPixelFromDIP(borderRadius); } if (index == 0) { view.setBorderRadius(borderRadius); } else { view.setBorderRadius(borderRadius, index - 1); } }
@ReactPropGroup(names = { ViewProps.BORDER_RADIUS, ViewProps.BORDER_TOP_LEFT_RADIUS, ViewProps.BORDER_TOP_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_LEFT_RADIUS }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderRadius(ReactHorizontalScrollView view, int index, float borderRadius) { if (!YogaConstants.isUndefined(borderRadius)) { borderRadius = PixelUtil.toPixelFromDIP(borderRadius); } if (index == 0) { view.setBorderRadius(borderRadius); } else { view.setBorderRadius(borderRadius, index - 1); } }
@ReactProp(name = PROP_SHADOW_OFFSET) public void setTextShadowOffset(@Nullable ReadableMap offsetMap) { float dx = 0; float dy = 0; if (offsetMap != null) { if (offsetMap.hasKey("width")) { dx = PixelUtil.toPixelFromDIP(offsetMap.getDouble("width")); } if (offsetMap.hasKey("height")) { dy = PixelUtil.toPixelFromDIP(offsetMap.getDouble("height")); } } if (!mShadowStyleSpan.offsetMatches(dx, dy)) { getShadowSpan().setOffset(dx, dy); notifyChanged(false); } }
@Override public long measure( YogaNode node, float width, YogaMeasureMode widthMode, float height, YogaMeasureMode heightMode) { // measure() should never be called before setThemedContext() EditText editText = Assertions.assertNotNull(mEditText); int fontSize = getFontSize(); editText.setTextSize( TypedValue.COMPLEX_UNIT_PX, fontSize == UNSET ? (int) Math.ceil(PixelUtil.toPixelFromSP(ViewDefaults.FONT_SIZE_SP)) : fontSize); if (mNumberOfLines != UNSET) { editText.setLines(mNumberOfLines); } editText.measure( MeasureUtil.getMeasureSpec(width, widthMode), MeasureUtil.getMeasureSpec(height, heightMode)); return YogaMeasureOutput.make(editText.getMeasuredWidth(), editText.getMeasuredHeight()); }
@ReactPropGroup(names = { ViewProps.BORDER_RADIUS, ViewProps.BORDER_TOP_LEFT_RADIUS, ViewProps.BORDER_TOP_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_LEFT_RADIUS }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderRadius(ReactEditText view, int index, float borderRadius) { if (!YogaConstants.isUndefined(borderRadius)) { borderRadius = PixelUtil.toPixelFromDIP(borderRadius); } if (index == 0) { view.setBorderRadius(borderRadius); } else { view.setBorderRadius(borderRadius, index - 1); } }
@Override public void onLayout() { int contentWidth = mEditText.getWidth(); int contentHeight = mEditText.getHeight(); // Use instead size of text content within EditText when available if (mEditText.getLayout() != null) { contentWidth = mEditText.getCompoundPaddingLeft() + mEditText.getLayout().getWidth() + mEditText.getCompoundPaddingRight(); contentHeight = mEditText.getCompoundPaddingTop() + mEditText.getLayout().getHeight() + mEditText.getCompoundPaddingBottom(); } if (contentWidth != mPreviousContentWidth || contentHeight != mPreviousContentHeight) { mPreviousContentHeight = contentHeight; mPreviousContentWidth = contentWidth; mEventDispatcher.dispatchEvent( new ReactContentSizeChangedEvent( mEditText.getId(), PixelUtil.toDIPFromPixel(contentWidth), PixelUtil.toDIPFromPixel(contentHeight))); } }
@ReactPropGroup(names = { ViewProps.BORDER_RADIUS, ViewProps.BORDER_TOP_LEFT_RADIUS, ViewProps.BORDER_TOP_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_LEFT_RADIUS }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderRadius(ReactTextView view, int index, float borderRadius) { if (!YogaConstants.isUndefined(borderRadius)) { borderRadius = PixelUtil.toPixelFromDIP(borderRadius); } if (index == 0) { view.setBorderRadius(borderRadius); } else { view.setBorderRadius(borderRadius, index - 1); } }
@ReactProp(name = PROP_SHADOW_OFFSET) public void setTextShadowOffset(ReadableMap offsetMap) { mTextShadowOffsetDx = 0; mTextShadowOffsetDy = 0; if (offsetMap != null) { if (offsetMap.hasKey(PROP_SHADOW_OFFSET_WIDTH) && !offsetMap.isNull(PROP_SHADOW_OFFSET_WIDTH)) { mTextShadowOffsetDx = PixelUtil.toPixelFromDIP(offsetMap.getDouble(PROP_SHADOW_OFFSET_WIDTH)); } if (offsetMap.hasKey(PROP_SHADOW_OFFSET_HEIGHT) && !offsetMap.isNull(PROP_SHADOW_OFFSET_HEIGHT)) { mTextShadowOffsetDy = PixelUtil.toPixelFromDIP(offsetMap.getDouble(PROP_SHADOW_OFFSET_HEIGHT)); } } markUpdated(); }
public void testScrollEvents() { HorizontalScrollView scrollView = getViewAtPath(0); dragLeft(); waitForBridgeAndUIIdle(); mScrollListenerModule.waitForScrollIdle(); waitForBridgeAndUIIdle(); ArrayList<Double> xOffsets = mScrollListenerModule.getXOffsets(); assertFalse("Expected to receive at least one scroll event", xOffsets.isEmpty()); assertTrue("Expected offset to be greater than 0", xOffsets.get(xOffsets.size() - 1) > 0); assertTrue( "Expected no item click event fired", mScrollListenerModule.getItemsPressed().isEmpty()); assertEquals( "Expected last offset to be offset of scroll view", PixelUtil.toDIPFromPixel(scrollView.getScrollX()), xOffsets.get(xOffsets.size() - 1).doubleValue(), 1e-5); }
@ReactPropGroup(names = { ViewProps.BORDER_RADIUS, ViewProps.BORDER_TOP_LEFT_RADIUS, ViewProps.BORDER_TOP_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_LEFT_RADIUS }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderRadius(ReactScrollView view, int index, float borderRadius) { if (!YogaConstants.isUndefined(borderRadius)) { borderRadius = PixelUtil.toPixelFromDIP(borderRadius); } if (index == 0) { view.setBorderRadius(borderRadius); } else { view.setBorderRadius(borderRadius, index - 1); } }
public void testScrollEvents() { ScrollView scrollView = getViewAtPath(0); dragUp(); waitForBridgeAndUIIdle(); mScrollListenerModule.waitForScrollIdle(); waitForBridgeAndUIIdle(); ArrayList<Double> yOffsets = mScrollListenerModule.getYOffsets(); assertFalse("Expected to receive at least one scroll event", yOffsets.isEmpty()); assertTrue("Expected offset to be greater than 0", yOffsets.get(yOffsets.size() - 1) > 0); assertTrue( "Expected no item click event fired", mScrollListenerModule.getItemsPressed().isEmpty()); assertEquals( "Expected last offset to be offset of scroll view", PixelUtil.toDIPFromPixel(scrollView.getScrollY()), yOffsets.get(yOffsets.size() - 1).doubleValue(), 1e-5); assertTrue("Begin and End Drag should be called", mScrollListenerModule.dragEventsMatch()); }
private void checkForKeyboardEvents() { getRootView().getWindowVisibleDisplayFrame(mVisibleViewArea); final int heightDiff = DisplayMetricsHolder.getWindowDisplayMetrics().heightPixels - mVisibleViewArea.bottom; if (mKeyboardHeight != heightDiff && heightDiff > mMinKeyboardHeightDetected) { // keyboard is now showing, or the keyboard height has changed mKeyboardHeight = heightDiff; WritableMap params = Arguments.createMap(); WritableMap coordinates = Arguments.createMap(); coordinates.putDouble("screenY", PixelUtil.toDIPFromPixel(mVisibleViewArea.bottom)); coordinates.putDouble("screenX", PixelUtil.toDIPFromPixel(mVisibleViewArea.left)); coordinates.putDouble("width", PixelUtil.toDIPFromPixel(mVisibleViewArea.width())); coordinates.putDouble("height", PixelUtil.toDIPFromPixel(mKeyboardHeight)); params.putMap("endCoordinates", coordinates); sendEvent("keyboardDidShow", params); } else if (mKeyboardHeight != 0 && heightDiff <= mMinKeyboardHeightDetected) { // keyboard is now hidden mKeyboardHeight = 0; sendEvent("keyboardDidHide", null); } }
public void testMarginUpdateDoesntForgetPreviousValue() { mCatalystInstance.getJSModule(ViewRenderingTestModule.class).renderMarginApplication(mRootTag); waitForBridgeAndUIIdle(); View view = getViewAtPath(mRootView); // before: margin: 10, marginLeft: 20 mCatalystInstance.getJSModule(ViewRenderingTestModule.class).updateMargins(); waitForBridgeAndUIIdle(); // after: margin: 15; it should not forget marginLeft was set to 20 int expectedMargin = Math.round(PixelUtil.toPixelFromDIP(15)); int expectedMarginLeft = Math.round(PixelUtil.toPixelFromDIP(20)); assertEquals(expectedMarginLeft, (int) view.getX()); assertEquals(expectedMargin, (int) view.getY()); }
@Override public long measure( YogaNodeAPI node, float width, YogaMeasureMode widthMode, float height, YogaMeasureMode heightMode) { // measure() should never be called before setThemedContext() EditText editText = Assertions.assertNotNull(mEditText); int fontSize = getFontSize(); editText.setTextSize( TypedValue.COMPLEX_UNIT_PX, fontSize == UNSET ? (int) Math.ceil(PixelUtil.toPixelFromSP(ViewDefaults.FONT_SIZE_SP)) : fontSize); if (mNumberOfLines != UNSET) { editText.setLines(mNumberOfLines); } editText.measure( MeasureUtil.getMeasureSpec(width, widthMode), MeasureUtil.getMeasureSpec(height, heightMode)); return YogaMeasureOutput.make(editText.getMeasuredWidth(), editText.getMeasuredHeight()); }
@Override public void receiveCommand(ReactViewGroup root, int commandId, @Nullable ReadableArray args) { switch (commandId) { case CMD_HOTSPOT_UPDATE: { if (args == null || args.size() != 2) { throw new JSApplicationIllegalArgumentException( "Illegal number of arguments for 'updateHotspot' command"); } if (Build.VERSION.SDK_INT >= 21) { float x = PixelUtil.toPixelFromDIP(args.getDouble(0)); float y = PixelUtil.toPixelFromDIP(args.getDouble(1)); root.drawableHotspotChanged(x, y); } break; } case CMD_SET_PRESSED: { if (args == null || args.size() != 1) { throw new JSApplicationIllegalArgumentException( "Illegal number of arguments for 'setPressed' command"); } root.setPressed(args.getBoolean(0)); break; } } }
@Override public void addView(CollapsingToolbarLayoutView parent, View child, int index) { super.addView(parent, child, index); if (child instanceof Toolbar) { Toolbar toolbar = (Toolbar) child; int toolbarHeight = (int) PixelUtil.toPixelFromDIP(height); CollapsingToolbarLayout.LayoutParams params = new CollapsingToolbarLayout.LayoutParams( CollapsingToolbarLayout.LayoutParams.MATCH_PARENT, toolbarHeight ); params.setCollapseMode(CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_PIN); toolbar.setLayoutParams(params); toolbar.requestLayout(); } }
@Override public void dispatch(RCTEventEmitter rctEventEmitter) { WritableMap data = Arguments.createMap(); data.putDouble("width", PixelUtil.toDIPFromPixel(mWidth)); data.putDouble("height", PixelUtil.toDIPFromPixel(mHeight)); rctEventEmitter.receiveEvent(getViewTag(), EVENT_NAME, data); }
public void smoothScrollToPosition(int position, final ScrollOptions options) { final RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(this.getContext()) { @Override protected int getVerticalSnapPreference() { return LinearSmoothScroller.SNAP_TO_START; } @Override public PointF computeScrollVectorForPosition(int targetPosition) { return ((LinearLayoutManager) this.getLayoutManager()).computeScrollVectorForPosition(targetPosition); } @Override protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { if (options.millisecondsPerInch != null) { return options.millisecondsPerInch / displayMetrics.densityDpi; } else { return super.calculateSpeedPerPixel(displayMetrics); } } @Override public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) { int calc = super.calculateDtToFit(viewStart, viewEnd, boxStart, boxEnd, snapPreference); if (options.viewPosition != null) { int viewHeight = viewEnd - viewStart; int boxHeight = boxEnd - boxStart; float viewOffset = options.viewOffset != null ? PixelUtil.toPixelFromDIP(options.viewOffset) : 0; float target = boxStart + (boxHeight - viewHeight) * options.viewPosition + viewOffset; return (int) (target - viewStart); } else { return super.calculateDtToFit(viewStart, viewEnd, boxStart, boxEnd, snapPreference); } } }; smoothScroller.setTargetPosition(position); this.getLayoutManager().startSmoothScroll(smoothScroller); }
private IconImageInfo getIconImageInfo(ReadableMap source) { if (source.hasKey("width") && source.hasKey("height")) { final int width = Math.round(PixelUtil.toPixelFromDIP(source.getInt("width"))); final int height = Math.round(PixelUtil.toPixelFromDIP(source.getInt("height"))); return new IconImageInfo(width, height); } else { return null; } }
@ReactProp(name = PROP_SHADOW_RADIUS) public void setTextShadowRadius(float textShadowRadius) { textShadowRadius = PixelUtil.toPixelFromDIP(textShadowRadius); if (mShadowStyleSpan.getRadius() != textShadowRadius) { getShadowSpan().setRadius(textShadowRadius); notifyChanged(false); } }
public void testMarginsApplied() { mCatalystInstance.getJSModule(ViewRenderingTestModule.class).renderMarginApplication(mRootTag); waitForBridgeAndUIIdle(); View view = getViewAtPath(mRootView); int expectedMargin = Math.round(PixelUtil.toPixelFromDIP(10)); int expectedMarginLeft = Math.round(PixelUtil.toPixelFromDIP(20)); assertEquals(expectedMarginLeft, (int) view.getX()); assertEquals(expectedMargin, (int) view.getY()); }
@Override public void setBorderWidths(int index, float borderWidth) { super.setBorderWidths(index, borderWidth); int type = SPACING_TYPES[index]; getMutableBorder().setBorderWidth(type, PixelUtil.toPixelFromDIP(borderWidth)); }
@ReactProp(name = "borderRadius") public void setBorderRadius(float borderRadius) { mClipRadius = borderRadius; if (mClipToBounds && borderRadius > DrawView.MINIMUM_ROUNDED_CLIPPING_VALUE) { // mount to a view if we are overflow: hidden and are clipping, so that we can do one // clipPath to clip all the children of this node (both DrawCommands and Views). forceMountToView(); } getMutableBorder().setBorderRadius(PixelUtil.toPixelFromDIP(borderRadius)); }
@ReactProp(name = ViewProps.LINE_HEIGHT, defaultDouble = Double.NaN) public void setLineHeight(double lineHeight) { if (Double.isNaN(lineHeight)) { mSpacingMult = 1.0f; mSpacingAdd = 0.0f; } else { mSpacingMult = 0.0f; mSpacingAdd = PixelUtil.toPixelFromSP((float) lineHeight); } notifyChanged(true); }
private WritableMap serializeEventData() { WritableMap contentInset = Arguments.createMap(); contentInset.putDouble("top", 0); contentInset.putDouble("bottom", 0); contentInset.putDouble("left", 0); contentInset.putDouble("right", 0); WritableMap contentOffset = Arguments.createMap(); contentOffset.putDouble("x", PixelUtil.toDIPFromPixel(mScrollX)); contentOffset.putDouble("y", PixelUtil.toDIPFromPixel(mScrollY)); WritableMap contentSize = Arguments.createMap(); contentSize.putDouble("width", PixelUtil.toDIPFromPixel(mContentWidth)); contentSize.putDouble("height", PixelUtil.toDIPFromPixel(mContentHeight)); WritableMap layoutMeasurement = Arguments.createMap(); layoutMeasurement.putDouble("width", PixelUtil.toDIPFromPixel(mScrollViewWidth)); layoutMeasurement.putDouble("height", PixelUtil.toDIPFromPixel(mScrollViewHeight)); WritableMap event = Arguments.createMap(); event.putMap("contentInset", contentInset); event.putMap("contentOffset", contentOffset); event.putMap("contentSize", contentSize); event.putMap("layoutMeasurement", layoutMeasurement); event.putInt("target", getViewTag()); event.putBoolean("responderIgnoreScroll", true); return event; }
@ReactProp(name = "hitSlop") public void setHitSlop(FlatViewGroup view, @Nullable ReadableMap hitSlop) { if (hitSlop == null) { view.setHitSlopRect(null); } else { view.setHitSlopRect(new Rect( (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("left")), (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("top")), (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("right")), (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("bottom")) )); } }
@Override public ReactEditText createViewInstance(ThemedReactContext context) { ReactEditText editText = new ReactEditText(context); int inputType = editText.getInputType(); editText.setInputType(inputType & (~InputType.TYPE_TEXT_FLAG_MULTI_LINE)); editText.setReturnKeyType("done"); editText.setTextSize( TypedValue.COMPLEX_UNIT_PX, (int) Math.ceil(PixelUtil.toPixelFromSP(ViewDefaults.FONT_SIZE_SP))); return editText; }
@ReactPropGroup(names = { ViewProps.BORDER_WIDTH, ViewProps.BORDER_LEFT_WIDTH, ViewProps.BORDER_RIGHT_WIDTH, ViewProps.BORDER_TOP_WIDTH, ViewProps.BORDER_BOTTOM_WIDTH, }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderWidth(ReactEditText view, int index, float width) { if (!YogaConstants.isUndefined(width)) { width = PixelUtil.toPixelFromDIP(width); } view.setBorderWidth(SPACING_TYPES[index], width); }
@Override public long measure( YogaNode node, float width, YogaMeasureMode widthMode, float height, YogaMeasureMode heightMode) { // measure() should never be called before setThemedContext() EditText editText = Assertions.assertNotNull(mEditText); editText.setTextSize( TypedValue.COMPLEX_UNIT_PX, mFontSize == UNSET ? (int) Math.ceil(PixelUtil.toPixelFromSP(ViewDefaults.FONT_SIZE_SP)) : mFontSize); if (mNumberOfLines != UNSET) { editText.setLines(mNumberOfLines); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (editText.getBreakStrategy() != mTextBreakStrategy) { editText.setBreakStrategy(mTextBreakStrategy); } } editText.measure( MeasureUtil.getMeasureSpec(width, widthMode), MeasureUtil.getMeasureSpec(height, heightMode)); return YogaMeasureOutput.make(editText.getMeasuredWidth(), editText.getMeasuredHeight()); }
/** * Creates catalyst pointers array in format that is expected by RCTEventEmitter JS module from * given {@param event} instance. This method use {@param reactTarget} parameter to set as a * target view id associated with current gesture. */ private static WritableArray createsPointersArray(int reactTarget, TouchEvent event) { WritableArray touches = Arguments.createArray(); MotionEvent motionEvent = event.getMotionEvent(); // Calculate the coordinates for the target view. // The MotionEvent contains the X,Y of the touch in the coordinate space of the root view // The TouchEvent contains the X,Y of the touch in the coordinate space of the target view // Subtracting them allows us to get the coordinates of the target view's top left corner // We then use this when computing the view specific touches below // Since only one view is actually handling even multiple touches, the values are all relative // to this one target view. float targetViewCoordinateX = motionEvent.getX() - event.getViewX(); float targetViewCoordinateY = motionEvent.getY() - event.getViewY(); for (int index = 0; index < motionEvent.getPointerCount(); index++) { WritableMap touch = Arguments.createMap(); // pageX,Y values are relative to the RootReactView // the motionEvent already contains coordinates in that view touch.putDouble(PAGE_X_KEY, PixelUtil.toDIPFromPixel(motionEvent.getX(index))); touch.putDouble(PAGE_Y_KEY, PixelUtil.toDIPFromPixel(motionEvent.getY(index))); // locationX,Y values are relative to the target view // To compute the values for the view, we subtract that views location from the event X,Y float locationX = motionEvent.getX(index) - targetViewCoordinateX; float locationY = motionEvent.getY(index) - targetViewCoordinateY; touch.putDouble(LOCATION_X_KEY, PixelUtil.toDIPFromPixel(locationX)); touch.putDouble(LOCATION_Y_KEY, PixelUtil.toDIPFromPixel(locationY)); touch.putInt(TARGET_KEY, reactTarget); touch.putDouble(TIMESTAMP_KEY, event.getTimestampMs()); touch.putDouble(POINTER_IDENTIFIER_KEY, motionEvent.getPointerId(index)); touches.pushMap(touch); } return touches; }