Blog

Drop shadow layer below UITextView

by Gwenn Guihal. 0 Comments

I needed a UITextView as textField. I decided to add an inner drop shadow at my textview to seem pretty cool :) It seems be easy to do : just add a drop shadowed CALayer below the textView and set masksToBounds to YES.

self.textView.layer.cornerRadius = 8.0;

self.shadowLayer = [[CALayer alloc] init];

self.shadowLayer.frame = self.textField.frame;
self.shadowLayer.cornerRadius = self.textView.layer.cornerRadius;
self.shadowLayer.borderColor = [UIColor lightGrayColor].CGColor;
self.shadowLayer.borderWidth = 1.5f;
self.shadowLayer.shadowColor = [UIColor blackColor].CGColor;
self.shadowLayer.shadowOpacity = 0.7;
self.shadowLayer.shadowOffset = CGSizeMake(2.0, 2.0);
self.shadowLayer.shadowRadius = 3.0;
self.shadowLayer.masksToBounds = YES;

[self.view.layer insertSublayer:self.shadowLayer above:self.textView.layer];

Capture d’écran 2013-03-19 à 10.44.54

Unfortunately, it doesn’t work :( I don’t know why, but some blinking appears and the behaviour of the caret isn’t normal. Sometimes a black rectangle appears above the text.
If I set the value of maskToBounds to NO, it works very well but my drop shadow overflows.

Capture d’écran 2013-03-19 à 10.48.57

To avoid that, the only solution I know is to add a mask to the layer.

CALayer *maskLayer = [[CALayer alloc] init];
maskLayer.anchorPoint = CGPointZero;
maskLayer.bounds = self.shadowLayer.bounds;
maskLayer.backgroundColor = [UIColor blackColor].CGColor;
maskLayer.cornerRadius = self.shadowLayer.cornerRadius;

[self.shadowLayer setMask:maskLayer];

Capture d’écran 2013-03-19 à 10.53.36

Done.

Java Native Interface for Android

by Gwenn Guihal.

What ?

JNI allows to use C++ code with Java, on Android for example.

For what ?

For few stuff :

  1. To not rewrite in Java a useful existing library.
  2. To use the same library on Android and IOS.
  3. At my mind, point 2 is essential.
  4. For many things, C++ is faster than Java.

How to proceed ?

Because I don’t know C++, I will be brief. I looked the AndEngine‘s guys job and reproduce it for my works.
You would only need to copy and edit two or three files, install Cygwin (with c++ extensions) if you are on Windows and that’s all !

Sample ?

Yes, print a random number in console : the best example never seen before.
1) Install the last improved Android NDK from Dmitry Moskalchuk aka CrystaX.
He says :

You shouldn’t care about wide chars/strings/streams anymore when porting existing code to Android – just compile it using my NDK and go further. Download and enjoy!

I used ndk6 for the sample.
2) Create a new android project in eclipse, call it « HelloJNI », choose SDK 2.1.
3) Create a folder « jni » and copy files from the same folder on the github repository.
4) The C++ lib is called myGreatLib and contains one function : « giveMeANumber »  which returns a random int.
5) Now, we have to write a little bit of java code! Create « HelloJNI.java » then declare required native and java methods.

// native methods
private native int jniGiveMeANumber();

// java methods
public void giveMeANumber()
{
	int num = jniGiveMeANumber();
	Log.e("JNI", "Number : " + num );
}

With this class, we generate a header C++ file with which we will write the C++ code to call our amazing lib.
Open a shell, go to HelloJNI/bin/classes then run command:

javah fr.myrddin.hellojni.HelloJNI

This command generates a C++ header file at the root of your bin/classes folder. Copy the « fr_myrddin_hellojni_HelloJNI.h » file into the « jni » folder and rename it « HelloJNI.h ».

Well done. We write now the cpp file HelloJNI.cpp from the generated header :

#include "HelloJNI.h"
#include "myGreatLib/Hello.cpp"

#ifdef ANDROID
#include
#endif

JNIEXPORT jint JNICALL Java_fr_myrddin_hellojni_HelloJNI_jniGiveMeANumber(JNIEnv *, jobject)
{
	Hello hello;
	return hello.giveMeANumber();
}

6) We just have to compile our C++ lib. For that, I took Android.mk, Application.mk, and build.sh files from the port of Box2D by Libgdx (Mario Zechner) and AndEngine (Nicolas Gramlich).
Edit Android.mk file :

...
LOCAL_MODULE := libHelloJNI
...
LOCAL_SRC_FILES := \
HelloJNI.cpp

Edit build.sh to set the project place and change the ndk folder by yours.
Run Cygwin, then launch build.sh.

Yes! It works! In the project, we have now a libs folder which contains the compiled lib : armeabi-v7a/libHelloJNI.so. Add it to build path.
Add that code in HelloJNI.java, it allows to load the library.

static
{
	System.loadLibrary("HelloJNI");
}

Edit HelloJNIActivity to test your library :

HelloJNI test = new HelloJNI();
test.giveMeANumber();

Compile and run, …, look at the console, …, it works, you are the best!

Next

For more information, look a these links :
Android NDK
What is the NDK?
The Java Native Interface, Programmer’s Guide and Specification

For more detailled samples, there is a couple of library of my github :
- AndroidClipper : JNI wrapper of Angus Johnson’s Polygon clipping library (my fist JNI library)
- Triangulate : JNI wrapper of John W. Ratcliff’s Triangulate library.*
- AndroidPoly2Tri : JNI wrapper of poly2tri, a 2D constrained Delaunay triangulation library.

Good luck !