Skip to content

Commit

Permalink
adding native codes
Browse files Browse the repository at this point in the history
  • Loading branch information
rghorbani committed Feb 17, 2018
1 parent bcd1c9c commit 99d2910
Show file tree
Hide file tree
Showing 22 changed files with 1,278 additions and 0 deletions.
18 changes: 18 additions & 0 deletions RNCommon.podspec
@@ -0,0 +1,18 @@
require "json"

package = JSON.parse(File.read(File.join(__dir__, "package.json")))

Pod::Spec.new do |s|
s.name = "RNCommon"
s.version = package["version"]
s.summary = "UI & API Components Library for React Native"
s.homepage = "https://github.com/rghorbani/react-native-common"
s.license = "MIT"
s.author = { "Reza Ghorbani" => "r.ghorbani.f@gmail.com" }
s.platform = :ios, "8.0"
s.source = { :git => "https://github.com/rghorbani/react-native-common.git", :tag => "master" }

s.source_files = "ios/**/*.{h,m}"

s.dependency "React"
end
24 changes: 24 additions & 0 deletions android/build.gradle
@@ -0,0 +1,24 @@

apply plugin: 'com.android.library'

android {
compileSdkVersion 23
buildToolsVersion "23.0.1"

defaultConfig {
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile 'com.facebook.react:react-native:+'
}
4 changes: 4 additions & 0 deletions android/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kajoo.reactnativecommon">
</manifest>
@@ -0,0 +1,34 @@

package com.kajoo.reactnativecommon.highlighterview;

import android.content.res.Resources;
import android.graphics.RectF;

import com.facebook.react.bridge.ReadableMap;

public class HighlightFrame {
public float x;
public float y;
public float width;
public float height;

public HighlightFrame(Resources resources, ReadableMap highlightFrameMap) {
if (highlightFrameMap != null) {
x = UiUtils.pxToDp(resources, highlightFrameMap.getDouble("x"));
y = UiUtils.pxToDp(resources, highlightFrameMap.getDouble("y"));
width = UiUtils.pxToDp(resources, highlightFrameMap.getDouble("width"));
height = UiUtils.pxToDp(resources, highlightFrameMap.getDouble("height"));
}
}

public HighlightFrame(float x, float y, float width, float height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}

public RectF toRect() {
return new RectF(x, y, x + width,y + height);
}
}
@@ -0,0 +1,51 @@

package com.kajoo.reactnativecommon.highlighterview;

import android.content.res.Resources;

import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;

public class HighlightViewTagParams {
public float paddingTop = 0;
public float paddingLeft = 0;
public float paddingBottom = 0;
public float paddingRight = 0;
public float offsetX = 0;
public float offsetY = 0;

public HighlightViewTagParams(Resources resources, ReadableMap highlightViewTagParams) {
if (highlightViewTagParams != null) {
if (highlightViewTagParams.hasKey("padding")) {
if (highlightViewTagParams.getType("padding") == ReadableType.Number) {
float paddingValue = UiUtils.pxToDp(resources, highlightViewTagParams.getDouble("padding"));
paddingTop = paddingLeft = paddingBottom = paddingRight = paddingValue;
} else if (highlightViewTagParams.getType("padding") == ReadableType.Map) {
ReadableMap paddingMap = highlightViewTagParams.getMap("padding");
if (paddingMap.hasKey("top")) {
paddingTop = UiUtils.pxToDp(resources, paddingMap.getDouble("top"));
}
if (paddingMap.hasKey("left")) {
paddingLeft = UiUtils.pxToDp(resources, paddingMap.getDouble("left"));
}
if (paddingMap.hasKey("bottom")) {
paddingBottom = UiUtils.pxToDp(resources, paddingMap.getDouble("bottom"));
}
if (paddingMap.hasKey("right")) {
paddingRight = UiUtils.pxToDp(resources, paddingMap.getDouble("right"));
}
}
}

if (highlightViewTagParams.hasKey("offset")) {
ReadableMap offsetMap = highlightViewTagParams.getMap("offset");
if (offsetMap.hasKey("x")) {
offsetX = UiUtils.pxToDp(resources, offsetMap.getDouble("x"));
}
if (offsetMap.hasKey("y")) {
offsetY = UiUtils.pxToDp(resources, offsetMap.getDouble("y"));
}
}
}
}
}
@@ -0,0 +1,133 @@

package com.kajoo.reactnativecommon.highlighterview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.support.annotation.ColorInt;
import android.view.View;

public class HighlighterView extends View {
private RectF highlightFrame;
private RectF viewBasedHighlightFrame;
HighlightViewTagParams highlightViewTagParams;
private @ColorInt int overlayColor;
private @ColorInt int strokeColor;
private float strokeWidth;
private float borderRadius = -1;
private float radius;

private static final PorterDuffXfermode porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
private static final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

public HighlighterView(Context context) {
super(context);
setLayerType(LAYER_TYPE_HARDWARE, null);
}

private RectF rectToDraw() {
if (viewBasedHighlightFrame != null && viewBasedHighlightFrame.width() > 0 && viewBasedHighlightFrame.height() > 0) {
if (highlightViewTagParams == null) {
return viewBasedHighlightFrame;
}

RectF highlightRect = new RectF(viewBasedHighlightFrame);
highlightRect.left -= highlightViewTagParams.paddingLeft;
highlightRect.top -= highlightViewTagParams.paddingTop;
highlightRect.right += highlightViewTagParams.paddingRight;
highlightRect.bottom += highlightViewTagParams.paddingBottom;

if (highlightViewTagParams.offsetX > 0) {
highlightRect.left += highlightViewTagParams.offsetX;
highlightRect.right += highlightViewTagParams.offsetX;
}
if (highlightViewTagParams.offsetY > 0) {
highlightRect.top += highlightViewTagParams.offsetY;
highlightRect.bottom += highlightViewTagParams.offsetY;
}
return highlightRect;
} else {
return highlightFrame;
}
}

private void updateRadius() {
float newRadius = 0;
if (borderRadius >= 0) {
newRadius = borderRadius;
}
else {
RectF rect = rectToDraw();
if (rect != null) {
newRadius = Math.min(rect.width() / 2, rect.height() / 2);
}
}
radius = newRadius;
}

public void setHighlightFrame(HighlightFrame frame) {
highlightFrame = frame.toRect();
updateRadius();
invalidate();
}

public void setOverlayColor(@ColorInt int overlayColor) {
this.overlayColor = overlayColor;
invalidate();
}

public void setStrokeColor(@ColorInt int strokeColor) {
this.strokeColor = strokeColor;
invalidate();
}

public void setStrokeWidth(int strokeWidth) {
this.strokeWidth = UiUtils.pxToDp(getResources(), strokeWidth);
invalidate();
}

public void setBorderRadius(int borderRadius) {
this.borderRadius = UiUtils.pxToDp(getResources(), borderRadius);
updateRadius();
invalidate();
}

public void setViewBasedHighlightFrame(HighlightFrame viewBasedHighlightFrame) {
this.viewBasedHighlightFrame = viewBasedHighlightFrame.toRect();
updateRadius();
invalidate();
}

public void setHighlightViewTagParams(HighlightViewTagParams highlightViewTagParams) {
this.highlightViewTagParams = highlightViewTagParams;
updateRadius();
invalidate();
}

@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);

paint.setColor(overlayColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawPaint(paint);

RectF rect = rectToDraw();
if(rect != null) {
paint.setXfermode(porterDuffXfermode);

canvas.drawRoundRect(rect, radius, radius, paint);

if (strokeWidth > 0) {
paint.setXfermode(null);
paint.setColor(strokeColor);
paint.setStrokeWidth(strokeWidth);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRoundRect(rect, radius, radius, paint);
}
}
}
}
@@ -0,0 +1,107 @@

package com.kajoo.reactnativecommon.highlighterview;

import android.app.Activity;
import android.graphics.Rect;
import android.util.Log;
import android.view.View;

import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.IllegalViewOperationException;
import com.facebook.react.uimanager.NativeViewHierarchyManager;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.annotations.ReactProp;

import javax.annotation.Nullable;

class HighlighterViewManager extends SimpleViewManager<HighlighterView> {
private static final String REACT_CLASS = "HighlighterView";

private ThemedReactContext context;

@Override
public String getName() {
return REACT_CLASS;
}

@Override
public HighlighterView createViewInstance(ThemedReactContext context) {
this.context = context;
return new HighlighterView(context);
}

@ReactProp(name = "highlightFrame")
public void setHighlightFrame(HighlighterView view, ReadableMap highlightFrame) {
view.setHighlightFrame(new HighlightFrame(view.getResources(), highlightFrame));
}

@ReactProp(name = "overlayColor")
public void setOverlayColor(HighlighterView view, @Nullable Integer overlayColor) {
view.setOverlayColor((overlayColor == null) ? 0 : overlayColor);
}

@ReactProp(name = "borderRadius")
public void setBorderRadius(HighlighterView view, @Nullable Integer borderRadius) {
view.setBorderRadius((borderRadius == null) ? 0 : borderRadius);
}

@ReactProp(name = "strokeColor")
public void setStrokeColor(HighlighterView view, @Nullable Integer strokeColor) {
view.setStrokeColor((strokeColor == null) ? 0 : strokeColor);
}

@ReactProp(name = "strokeWidth")
public void setStrokeWidth(HighlighterView view, @Nullable Integer strokeWidth) {
view.setStrokeWidth((strokeWidth == null) ? 0 : strokeWidth);
}

@ReactProp(name = "highlightViewTag")
public void setHighlightViewTag(final HighlighterView view, Integer highlightViewTag) {
try {
NativeViewHierarchyManager nativeViewHierarchyManager = ReactHacks.getNativeViewHierarchyManager(context.getNativeModule(UIManagerModule.class));
if (nativeViewHierarchyManager == null) {
return;
}

final View resolvedView = nativeViewHierarchyManager.resolveView(highlightViewTag);
if (resolvedView != null) {
if (resolvedView.getWidth() == 0 || resolvedView.getHeight() == 0) {
resolvedView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
float width = right - left;
float height = bottom - top;
if (width > 0 && height > 0) {
setViewBasedHighlightFrame(view, resolvedView);
resolvedView.removeOnLayoutChangeListener(this);
}
}
});
} else {
setViewBasedHighlightFrame(view, resolvedView);
}
}
}
catch (IllegalViewOperationException e) {
Log.e("HighlighterView", "invalid highlightViewTag: " + highlightViewTag.toString() + " " + e.toString());
}
}

@ReactProp(name = "highlightViewTagParams")
public void setHighlightViewTagParams(HighlighterView view, ReadableMap highlightViewTagParams) {
view.setHighlightViewTagParams(new HighlightViewTagParams(view.getResources(), highlightViewTagParams));
}

private void setViewBasedHighlightFrame(HighlighterView view, View resolvedView) {
Activity currentActivity = context.getCurrentActivity();
if (currentActivity == null) {
return;
}

final float topOffset = UiUtils.getStatusBarHeight(view, currentActivity.getWindow());
Rect myViewRect = UiUtils.getVisibleRect(resolvedView);
view.setViewBasedHighlightFrame(new HighlightFrame(myViewRect.left, myViewRect.top - topOffset, resolvedView.getWidth(), resolvedView.getHeight()));
}
}

0 comments on commit 99d2910

Please sign in to comment.