This post is available on my new blog. Take me there.
Android And SharePoint Geeks
A technology blog for SharePoint and Android developers.
Monday 25 June 2018
Thursday 29 March 2018
Brainfuck Program Interpreter
This is a Brainf**k interpreter developed by me to help people check their outputs. If you need some help with the language checkout my blog on the topic. Please keep in mind following limitations and features of this interpreter :
Saturday 1 April 2017
How to write/draw on device screen using finger
Hey Reader!
I am moving to a new site. Please click here to find this blog.
Sorry for the inconvinience.
I am moving to a new site. Please click here to find this blog.
Sorry for the inconvinience.
Saturday 30 April 2016
Android - Move/Drag views inside RelativeLayout
Ever wondered how can we move or drag a view inside a view group? Well it's very simple actually. Let's consider we have an Activity with RelativeLayout as root view group and inside that we have a View like this :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rlroot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<View
android:id="@+id/v_red"
android:layout_height="@dimen/square_size"
android:layout_width="@dimen/square_size"
android:background="@color/red"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"/>
</RelativeLayout>
You can have anything in place of view like Button or TextView. Create an object of RelativeLayout and View both in onCreate of your activity :xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rlroot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<View
android:id="@+id/v_red"
android:layout_height="@dimen/square_size"
android:layout_width="@dimen/square_size"
android:background="@color/red"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"/>
</RelativeLayout>
View view_r;
int xDelta,yDelta;
RelativeLayout rootLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rootLayout = (RelativeLayout) findViewById(R.id.rlroot);
view_r = findViewById(R.id.v_red);
view_r.setOnTouchListener(this);
}
Since we set activity as the onTouchListener for view, implement View.onTouchListener on your activity. Then implement onTouch method like this :int xDelta,yDelta;
RelativeLayout rootLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rootLayout = (RelativeLayout) findViewById(R.id.rlroot);
view_r = findViewById(R.id.v_red);
view_r.setOnTouchListener(this);
}
@Overridepublic boolean onTouch(View v, MotionEvent event) {
final int X = (int) event.getRawX(); //X coordinate of where you actually touched on screen
final int Y = (int) event.getRawY(); //Y coordinate of where you actually touched on screen
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
Log.d("MainActivity","leftPos:"+v.getLeft()+"topPos:"+v.getTop());
//this portion calculates where or how far inside have we touched the view from it's top left corner.
xDelta = X - lParams.leftMargin;
yDelta = Y - lParams.topMargin; Log.d("MainActivity","Action_Down:X="+X+",Y="+Y+",xD="+xDelta+",yD="+yDelta+",lm="+lParams.leftMargin+",tm="+lParams.topMargin);
break;
case MotionEvent.ACTION_UP:
Log.d("MainActivity","Action_up");
break;
case MotionEvent.ACTION_POINTER_DOWN:
Log.d("MainActivity","Action_Pointer_Down");
break;
case MotionEvent.ACTION_POINTER_UP:
Log.d("MainActivity","Action_Pointer_Up");
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
layoutParams.leftMargin = X - xDelta;
layoutParams.topMargin = Y - yDelta;
layoutParams.rightMargin = 0;
layoutParams.bottomMargin = 0;
Log.d("MainActivity","mw="+rootLayout.getMeasuredWidth()+",mh="+rootLayout.getMeasuredHeight());
v.setLayoutParams(layoutParams);
//v.animate().x(X-xDelta).y(Y-yDelta).setDuration(0).start();
Log.d("MainActivity","Action_Move:X="+X+",Y="+Y+",xD="+xDelta+",yD="+yDelta);
break;
}
rootLayout.invalidate(); //to ask android to redraw the view
return true;
}
final int X = (int) event.getRawX(); //X coordinate of where you actually touched on screen
final int Y = (int) event.getRawY(); //Y coordinate of where you actually touched on screen
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
Log.d("MainActivity","leftPos:"+v.getLeft()+"topPos:"+v.getTop());
//this portion calculates where or how far inside have we touched the view from it's top left corner.
xDelta = X - lParams.leftMargin;
yDelta = Y - lParams.topMargin; Log.d("MainActivity","Action_Down:X="+X+",Y="+Y+",xD="+xDelta+",yD="+yDelta+",lm="+lParams.leftMargin+",tm="+lParams.topMargin);
break;
case MotionEvent.ACTION_UP:
Log.d("MainActivity","Action_up");
break;
case MotionEvent.ACTION_POINTER_DOWN:
Log.d("MainActivity","Action_Pointer_Down");
break;
case MotionEvent.ACTION_POINTER_UP:
Log.d("MainActivity","Action_Pointer_Up");
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
layoutParams.leftMargin = X - xDelta;
layoutParams.topMargin = Y - yDelta;
layoutParams.rightMargin = 0;
layoutParams.bottomMargin = 0;
Log.d("MainActivity","mw="+rootLayout.getMeasuredWidth()+",mh="+rootLayout.getMeasuredHeight());
v.setLayoutParams(layoutParams);
//v.animate().x(X-xDelta).y(Y-yDelta).setDuration(0).start();
Log.d("MainActivity","Action_Move:X="+X+",Y="+Y+",xD="+xDelta+",yD="+yDelta);
break;
}
rootLayout.invalidate(); //to ask android to redraw the view
return true;
}
This diagram will help you understand what are X, Y, XDelta and YDelta.
From above figure clearly X - XDelta gives the left margin that our view should have. Similarly Top Margin is equal to Y - YDelta.
The result is something like this :
But we are not going to stop here. As usual we will checkout a more complicated scenario.
What if I have 4 views inside RelativeLayout and each view takes a spot in each corner of RelativeLayout like this :
Here is the xml layout :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rlroot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
>
<View
android:id="@+id/v_red"
android:layout_height="@dimen/square_size"
android:layout_width="@dimen/square_size"
android:background="@color/red"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"/>
<View
android:id="@+id/v_blue"
android:layout_height="@dimen/square_size"
android:layout_width="@dimen/square_size"
android:background="@color/blue"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
/>
<View
android:id="@+id/v_green"
android:layout_height="@dimen/square_size"
android:layout_width="@dimen/square_size"
android:background="@color/green"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"/>
<View
android:id="@+id/v_other"
android:layout_height="@dimen/square_size"
android:layout_width="@dimen/square_size"
android:background="@color/other"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"/>
</RelativeLayout>
While working on a similar scenario what I found out was that LayoutParams.leftMargin always returned zero so above code failed. And the reason was attributes of View alignParentBottom, alignParentLeft etc. If you remove these attributes from all views it would work fine. But practically we would never want all views to be overlapped. So I found another way.xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rlroot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
>
<View
android:id="@+id/v_red"
android:layout_height="@dimen/square_size"
android:layout_width="@dimen/square_size"
android:background="@color/red"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"/>
<View
android:id="@+id/v_blue"
android:layout_height="@dimen/square_size"
android:layout_width="@dimen/square_size"
android:background="@color/blue"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
/>
<View
android:id="@+id/v_green"
android:layout_height="@dimen/square_size"
android:layout_width="@dimen/square_size"
android:background="@color/green"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"/>
<View
android:id="@+id/v_other"
android:layout_height="@dimen/square_size"
android:layout_width="@dimen/square_size"
android:background="@color/other"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"/>
</RelativeLayout>
On "ACTION_DOWN" I removed those attributes and calculated the view's initial margin and set them programtically. Note that if you only remove those attributes and not set initial margin then the view would just jump to left top corner the moment you touch it. Here is the code :
@Override
public boolean onTouch(View v, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
if(lParams.getRule(RelativeLayout.ALIGN_PARENT_BOTTOM)==RelativeLayout.TRUE)
{
lParams.topMargin = v.getTop();
lParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,0);
Log.d("MainActivity","added Rule bottom");
}
if(lParams.getRule(RelativeLayout.ALIGN_PARENT_TOP)==RelativeLayout.TRUE)
{
lParams.bottomMargin = v.getBottom();
lParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,0);
Log.d("MainActivity","added Rule top");
}
if(lParams.getRule(RelativeLayout.ALIGN_PARENT_LEFT)==RelativeLayout.TRUE)
{
lParams.rightMargin = v.getRight();
lParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,0);
Log.d("MainActivity","added Rule left");
}
if(lParams.getRule(RelativeLayout.ALIGN_PARENT_RIGHT)==RelativeLayout.TRUE)
{
lParams.leftMargin = v.getLeft();//rootLayout.getMeasuredWidth()-v.getWidth();
lParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,0);
Log.d("MainActivity","added Rule right");
}
Log.d("MainActivity","leftPos:"+v.getLeft()+"topPos:"+v.getTop());
xDelta = X - lParams.leftMargin;
yDelta = Y - lParams.topMargin;
Log.d("MainActivity","Action_Down:X="+X+",Y="+Y+",xD="+xDelta+",yD="+yDelta+",lm="+lParams.leftMargin+",tm="+lParams.topMargin);
break;
case MotionEvent.ACTION_UP:
Log.d("MainActivity","Action_up");
break;
case MotionEvent.ACTION_POINTER_DOWN:
Log.d("MainActivity","Action_Pointer_Down");
break;
case MotionEvent.ACTION_POINTER_UP:
Log.d("MainActivity","Action_Pointer_Up");
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
layoutParams.leftMargin = X - xDelta;
layoutParams.topMargin = Y - yDelta;
layoutParams.rightMargin = 0;
layoutParams.bottomMargin = 0;
v.setLayoutParams(layoutParams);
//v.animate().x(X-xDelta).y(Y-yDelta).setDuration(0).start();
Log.d("MainActivity","Action_Move:X="+X+",Y="+Y+",xD="+xDelta+",yD="+yDelta);
break;
}
rootLayout.invalidate();
return true;
}
public boolean onTouch(View v, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
if(lParams.getRule(RelativeLayout.ALIGN_PARENT_BOTTOM)==RelativeLayout.TRUE)
{
lParams.topMargin = v.getTop();
lParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,0);
Log.d("MainActivity","added Rule bottom");
}
if(lParams.getRule(RelativeLayout.ALIGN_PARENT_TOP)==RelativeLayout.TRUE)
{
lParams.bottomMargin = v.getBottom();
lParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,0);
Log.d("MainActivity","added Rule top");
}
if(lParams.getRule(RelativeLayout.ALIGN_PARENT_LEFT)==RelativeLayout.TRUE)
{
lParams.rightMargin = v.getRight();
lParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,0);
Log.d("MainActivity","added Rule left");
}
if(lParams.getRule(RelativeLayout.ALIGN_PARENT_RIGHT)==RelativeLayout.TRUE)
{
lParams.leftMargin = v.getLeft();//rootLayout.getMeasuredWidth()-v.getWidth();
lParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,0);
Log.d("MainActivity","added Rule right");
}
Log.d("MainActivity","leftPos:"+v.getLeft()+"topPos:"+v.getTop());
xDelta = X - lParams.leftMargin;
yDelta = Y - lParams.topMargin;
Log.d("MainActivity","Action_Down:X="+X+",Y="+Y+",xD="+xDelta+",yD="+yDelta+",lm="+lParams.leftMargin+",tm="+lParams.topMargin);
break;
case MotionEvent.ACTION_UP:
Log.d("MainActivity","Action_up");
break;
case MotionEvent.ACTION_POINTER_DOWN:
Log.d("MainActivity","Action_Pointer_Down");
break;
case MotionEvent.ACTION_POINTER_UP:
Log.d("MainActivity","Action_Pointer_Up");
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
layoutParams.leftMargin = X - xDelta;
layoutParams.topMargin = Y - yDelta;
layoutParams.rightMargin = 0;
layoutParams.bottomMargin = 0;
v.setLayoutParams(layoutParams);
//v.animate().x(X-xDelta).y(Y-yDelta).setDuration(0).start();
Log.d("MainActivity","Action_Move:X="+X+",Y="+Y+",xD="+xDelta+",yD="+yDelta);
break;
}
rootLayout.invalidate();
return true;
}
As you can see below we can move the views around...
Please note that we can use animate method also to move view (this is commented in above code)
//v.animate().x(X-xDelta).y(Y-yDelta).setDuration(0).start();
Cool right? Now we know how to drag views around.
Stay tuned for the next article. Till then keep rocking!
Android : A lesson on Regular Expressions by examples
Every one who has ever worked on Regular Expressions knows tricky it can be (if you don't understand it completely!). And as frustrated and angry as we might be, we can't ignore how powerful regular expressions are. Now let me put this straight first. I don't plan to pretend here that I am an expert on Regular Expressions. In this blog I am going to share with you what I have learned after spending countless hours in frustration. I am going explain Regular Expressions with practical examples that you may face at your work. So if you want to brush up your memory on RegEx characters\symbols you can check my blog on Regular Expressions (although that blog was for PowerShell, symbols have same meaning). Or there are some excellent articles on Regular Expressions that you can go through first like this.
Now that you have basics let's see some practical examples :
Let's say you have to find a name from a given string. Now we know names start with uppercase character. So our question boils down to this : Write a regular expression to find words that start with uppercase character followed by lowercase characters?
Solution: Now there are multiple ways to achieve this. I will show you 2 ways.
1- [A-Z][a-z]+
2- \p{Lu}\p{Ll}+
If you have gone through the 2nd link I shared above carefully which happens to be google's documentation on Pattern you can atleast recognize the strange symbols in second solution.
What first solution tells is find all strings with uppercase characters followed by lowercase characters. It's as simple as that. "+" tells preceding character or group may occur one or more times.
Now second solution is an advanced and cleaner way of doing same thing. \p let's you select characters based on the class name you provide inside curly braces following it. In above example Lu and Ll mean uppercase letter and lowercase letter respectively. Please note in android you have to use extra escape characters. So regex would be something like \\p{Lu}\\p{Ll}+ while compiling it using Pattern class. So our code would look like this :
Now that you have basics let's see some practical examples :
Let's say you have to find a name from a given string. Now we know names start with uppercase character. So our question boils down to this : Write a regular expression to find words that start with uppercase character followed by lowercase characters?
Solution: Now there are multiple ways to achieve this. I will show you 2 ways.
1- [A-Z][a-z]+
2- \p{Lu}\p{Ll}+
If you have gone through the 2nd link I shared above carefully which happens to be google's documentation on Pattern you can atleast recognize the strange symbols in second solution.
What first solution tells is find all strings with uppercase characters followed by lowercase characters. It's as simple as that. "+" tells preceding character or group may occur one or more times.
Now second solution is an advanced and cleaner way of doing same thing. \p let's you select characters based on the class name you provide inside curly braces following it. In above example Lu and Ll mean uppercase letter and lowercase letter respectively. Please note in android you have to use extra escape characters. So regex would be something like \\p{Lu}\\p{Ll}+ while compiling it using Pattern class. So our code would look like this :
String test = "this is some random text to test REGEX
Asutosh Nayak"
Pattern pattern_u =
Pattern.compile("[A-Z][a-z]+");//\p{Lu}\p{Ll}+
Matcher matcher_t = pattern_u.matcher(test);
String res = "";
int c = 0;
while(matcher_t.find())
{
res +=
"Match:"+matcher_t.group();
}
res +=
"\n";
}
textview_test.setText(res);To understand how group() works let's see this example :
String test = "this is some random text to test REGEX
Asutosh Nayak"
Pattern pattern_u =
Pattern.compile("[A-Z][a-z]+");//\p{Lu}\p{Ll}+
Matcher matcher_t = pattern_u.matcher(test);
String res = "";
int c = 0;
while(matcher_t.find())
{
res +=
"Match:"+matcher_t.group();
}
res +=
"\n";
}
textview_test.setText(res);
It gives result like this :
As you can see “Group No.1” returned “REGEX” which was found
by regex within first pair of parentheses and “Group No.2” returned “Asutosh”
which was our second group. For those of who are wondering what happened to
“Nayak” note that our regex was for a word with all uppercase characters
followed by a word with first character uppercase only.
Neat right? Not so difficult. But this was one of the
simplest regular expressions. Now let’s write some RegEx on numbers. Nothing
is complete without numbers.
What if you had a string and you wanted to find numbers in
it but not just any number. An amount in "Rupees" or "INR". So our regex should be capable of finding numbers preceded by Rs or
INR.
Solution : (?i)(?:\s(?:RS|INR)\.?\s?)(\d+(\.\d{1,2})?)
Here is the sample code :
String test = "this is some
random text to test REGEX for amount Rs. 911.10. Let's see 909.98."
Pattern pattern_m =
Pattern.compile("(?i)(?:\\s(?:RS|INR)\\.?\\s?)(\\d+(\\\\d{1,2})?)");
Pattern.compile("(?i)(?:\\s(?:RS|INR)\\.?\\s?)(\\d+(\\\\d{1,2})?)");
Matcher matcher_t =
pattern_m.matcher(test);
String
res = "";
int c = 0;
while(matcher_t.find())
{
res +=
"Match No."+ c++ +"\n";
for(int
i=0; i<=matcher_t.groupCount();i++)
{
res +=
" Group No."+i+"\n";
res +=
"
Match:"+matcher_t.group(i)+"\n";
}
res +=
"\n";
}
tv_test.setText(res);
It’s perfectly fine to panic! :-D. I will explain everything.
- (?i) - This tells that the regex that follows is case insensitive. So this regex will treat “RS” and “Rs” the same way. If later you want to add a group to your regex which is case sensitive just add a (?-i) before it.
- (?:)- This is called non capturing group. What it means is it will search for the patter that’s inside the parenthesis to determine the overall match but it won’t include this pattern in any group. As seen in above image.
- \.?- ‘?’ is called optional quantifier. It means the character or group preceding it can occur at most once(0 or 1). So here it tells that “Rs” can be followed by a “.”.
- (\d+(\.\d{1,2})?)- This pattern is used to recognize any decimal number. \d+ means one or more number of digits. So digits followed by pattern for period followed by 1 or 2 (at most) digits which is optional since numbers may not have decimal portion.
That’s all there is to it. These were the confusing symbols
in this regex.
Let’s make it even tougher. What if your string has now two
numbers and you want to get the ordinary number not the money value. So we have to build a regular expression to
find a number which is not preceded by Rs or INR. Sample String : "this is
some random text to test REGEX for amount Rs. 911.10. Let's see 909.98
Test."
Solution: (?i)[^(Rs|INR\.?\s?)](\s\d+(\.\d{1,2})?\s?)
Tip: while
writing complicated regular expressions always try to start small. Like if you
have to find numbers not preceded by Rs or INR try first finding Rs or INR,
then find numbers with Rs or INR and then finally negate the Rs or INR group.
This will help you find which portion of regex is not working.
All we did was surround the regex for finding "Rs or INR"
with within square brackets and add an "^" to it. "^" is like logical NOT. So
it signifies that we want numbers which are not preceded by Rs or INR.
Subscribe to:
Posts (Atom)