Getting screen coordinates with layout weight property - android - android

In my app activity, I have 8 buttons, 1 textView , 2 relative layouts and 1 linear layout(parent).
This is what it looks like:
Here is the structure:
< Linear Layout >
.........< Relative Layout 1 .....weight= 0.5>
.................< Button 1 >
.................< Button 2 >
.................< Button 3 >
.................< Button 4 >
.................< TextView "Touch a button">
.........< \Relative Layout>
.........< Relative Layout 2 .....weight= 0.5>
.................< Button 5 >
.................< Button 6 >
.................< Button 7 >
.................< Button 8 >
.........< \Relative Layout>
< Linear Layout >
As you might have guessed from the title, I am trying to get the coordinates of all the 8 buttons and detect if my finger is over any one of them while it moves through the screen.
I am able to get the coordinates of the buttons using the code given below but its not working properly. According to my code, the buttons should change their background color to red once they have been touched or hovered over. But what's happening is that buttons 5,6,7 and 8 do not recognize my touch and 1,2,3,4 do recognize it but they change their parallel button's color too. For instance if I touch B8, nothing happens but if I touch B4 it changes color along with B8.
To better explain I have put an image below. This image represents what happens when I touch B4:
Why is this happening? What maybe the prob? Please help me solve it.
Here is my code:
Main_Activity.java
public class MainActivity extends Activity {
MyButton b1, b2, b3, b4,b5,b6,b7,b8;
private TextView buttonIndicator;
private LinearLayout touchview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonIndicator = (TextView) findViewById(R.id.textView);
touchview = (LinearLayout) findViewById(R.id.linearlayout);
b1 = (MyButton) findViewById(R.id.button1);
b2 = (MyButton) findViewById(R.id.button2);
b3 = (MyButton) findViewById(R.id.button3);
b4 = (MyButton) findViewById(R.id.button4);
b5 = (MyButton) findViewById(R.id.button5);
b6 = (MyButton) findViewById(R.id.button6);
b7 = (MyButton) findViewById(R.id.button7);
b8 = (MyButton) findViewById(R.id.button8);
RelativeLayout touch1 = (RelativeLayout) findViewById(R.id.touchview1);
RelativeLayout touch2 = (RelativeLayout) findViewById(R.id.touchview2);
touch1.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return false; // To pass touch event to linear layout parent
}
});
touch2.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return false; // To pass touch event to linear layout parent
}
});
}
#Override
protected void onResume() {
super.onResume();
touchview.setOnTouchListener(new View.OnTouchListener() {
private boolean isInside = false;
#Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
if (isPointWithin(x, y, b1.getLeft(), b1.getRight(), b1.getTop(),b1.getBottom())) {
b1.setBackgroundColor(Color.RED);
buttonIndicator.setText("Button 1");
}
if (isPointWithin(x, y, b2.getLeft(), b2.getRight(), b2.getTop(),b2.getBottom())) {
b2.setBackgroundColor(Color.RED);
buttonIndicator.setText("Button 2");
}
if (isPointWithin(x, y, b3.getLeft(), b3.getRight(), b3.getTop(),b3.getBottom())) {
b3.setBackgroundColor(Color.RED);
buttonIndicator.setText("Button 3");
}
if (isPointWithin(x, y, b4.getLeft(), b4.getRight(), b4.getTop(),b4.getBottom())) {
b4.setBackgroundColor(Color.RED);
buttonIndicator.setText("Button 4");
}
if (isPointWithin(x, y, b5.getLeft(), b5.getRight(), b5.getTop(),b5.getBottom())) {
b5.setBackgroundColor(Color.RED);
buttonIndicator.setText("Button 5");
}
if (isPointWithin(x, y, b6.getLeft(), b6.getRight(), b6.getTop(),b6.getBottom())) {
b6.setBackgroundColor(Color.RED);
buttonIndicator.setText("Button 6");
}
if (isPointWithin(x, y, b7.getLeft(), b7.getRight(), b7.getTop(),b7.getBottom())) {
b7.setBackgroundColor(Color.RED);
buttonIndicator.setText("Button 7");
}
if (isPointWithin(x, y, b8.getLeft(), b8.getRight(), b8.getTop(),b8.getBottom())) {
b8.setBackgroundColor(Color.RED);
buttonIndicator.setText("Button 8");
}
return true;
}
});
}
//The boolean below determines the exact position of the finger on the screen
static boolean isPointWithin(int x, int y, int x1, int x2, int y1, int y2) {
return (x <= x2 && x >= x1 && y <= y2 && y >= y1);
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linearlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="1.0"
android:background="#ffffff" >
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#+id/touchview1"
android:layout_weight="0.5">
<com.example.coordinates.MyButton
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="B1"
android:layout_marginBottom="10dp"
android:textColor="#000000" />
<com.example.coordinates.MyButton
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="#+id/button1"
android:layout_marginBottom="10dp"
android:text="B2"
android:textColor="#000000" />
<com.example.coordinates.MyButton
android:id="#+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="#+id/button2"
android:text="B3"
android:layout_marginBottom="10dp"
android:textColor="#000000" />
<com.example.coordinates.MyButton
android:id="#+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="#+id/button3"
android:text="B4"
android:textColor="#000000" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Touch a button"
android:layout_marginLeft="10dp"
android:layout_marginBottom="10dp"
android:id="#+id/textView"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true" />
</RelativeLayout>
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#+id/touchview2"
android:layout_weight="0.5">
<com.example.coordinates.MyButton
android:id="#+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="B5"
android:layout_marginBottom="10dp"
android:textColor="#000000" />
<com.example.coordinates.MyButton
android:id="#+id/button6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="#+id/button5"
android:layout_marginBottom="10dp"
android:text="B6"
android:textColor="#000000" />
<com.example.coordinates.MyButton
android:id="#+id/button7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="#+id/button6"
android:text="B7"
android:layout_marginBottom="10dp"
android:textColor="#000000" />
<com.example.coordinates.MyButton
android:id="#+id/button8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="#+id/button7"
android:text="B8"
android:textColor="#000000" />
</RelativeLayout>
</LinearLayout>
MyButton.java
public class MyButton extends Button {
//I am using cutom Button to avoid ontouch for buttons and return false
public MyButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public MyButton(Context context) {
super(context);
// // TODO Auto-generated constructor stub
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
// return super.onTouchEvent(event);
return false;
}
}
I have tried my best to explain my problem. Please help me!
Thank you all very very much.
Edit : I was suggested to use View.getLocationOnScreen(). Can anyone please explain me how to get (x1 and x2) & (y1 and y2) coordinates with the help of this method? I think the image below explains it better!

getLeft() returns left border relative to parent. You should recursively add getLeft() of all parents as well.
Explained differently: both b4 and b8 return the same number for getLeft() call. if you want their absolute screen coordinates, see
How to get the absolute coordinates of a view
int pos[] = new int[2];
button.getLocationOnScreen(pos);
int x1 = pos[0], y1 = pos[1];
int x2 = x1 + button.getWidth();
int y2 = y1 + button.getHeight();

check this code
private boolean checkInterSection(View view, int rawX, int raxY) {
int[] location = new int[2];
view.getLocationOnScreen(location);
int x = location[0];
int y = location[1];
int width = view.getWidth();
int height = view.getHeight();
//Check the intersection of point with rectangle achieved
return (!(rawX < x || rawY > x + width || rawY < y || rawY > y + height)); }
for(int i = 0; i < touchview.getChildCount(); i++){
if(checkInterSection(touchview.getChildAt(i), event.getRawX(), event.getRawY())){
if(checkInterSection(touchview.getChildAt(i), event.getRawX(), event.getRawY())){
((Button)touchview.getChildAt(i)).setBackgroundColor(Color.BLUE);// Type casting may not be required
}else{
((Button)touchview.getChildAt(i)).setBackgroundColor(Color.WHITE);
}
break;
} }
From this link. And check the Answer posted by #Rajesh CP. I guess this is what exactly you need hope this helps you.

Related

How to display and click on buttons in a specified location on the screen?

I have written an app that shows 3 ImageViews in specified locations and by clicking on these buttons the user can navigate through the app.
To do that, first I used Bitmaps, it worked well for all type of the screens, but the problem was the memory overhead so I changed my method.
here is my code: I place ImageViews with specified with and height (in dp) and use the method "getArea" to determine which Image the user clicks, the problem is that the app interface is different on several phones and specially tablets (it does not recognizes the clicks)
my question: isn't it that "dp" is pixel independent? shouldn't it be the same on all devices? what is your suggestion in my case?
MainLayout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/my_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.arghavan.lenovo.autismo.main.MainActivity">
<ImageView
android:id="#+id/image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitXY"
android:src="#drawable/main_page_background"
/>
<ImageView
android:id="#+id/balloon"
android:layout_width="190dp"
android:layout_height="270dp"
android:scaleType="fitXY"
android:src="#drawable/main_page_balloon"
android:layout_gravity="center"
android:visibility="invisible"
/>
<ImageView
android:id="#+id/rainbow"
android:layout_width="200dp"
android:layout_height="200dp"
android:scaleType="fitXY"
android:src="#drawable/main_page_rainbow"
android:layout_gravity="top|left"
android:visibility="invisible"
/>
<ImageView
android:id="#+id/sun"
android:layout_width="150dp"
android:layout_height="150dp"
android:scaleType="fitXY"
android:src="#drawable/main_page_sun"
android:layout_gravity="top|right"
android:visibility="invisible"
/>
<Button
android:id="#+id/sound_icon"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_gravity="bottom|right"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
/>
</FrameLayout>
in MainActivity:
public void onTouch (View v, MotionEvent ev)
{
final int action = ev.getAction();
final int evX = (int) ev.getX();
final int evY = (int) ev.getY();
// If we cannot find the imageView, return.
ImageView imageView = (ImageView) v.findViewById (R.id.image);
if (imageView == null) return false;
switch (action) {
case MotionEvent.ACTION_DOWN :
int area = getArea(evX,evY);
if (area==1)
{
//do something
}
else if (area==2)
{
//do something
}
else if (area==3)
{
//do something
}
break;
default:
//do something
} // end switch
}
private int getArea(float x, float y)
{
float density = getResources().getDisplayMetrics().density;
float rx = x / density;
float ry = y / density;
if( 20< rx && rx<196 && 15<ry && ry< 159 )
return 1;
if( 86< rx && rx<293 && 138<ry && ry< 384 )
return 2;
if( 224< rx && rx<352 && 13<ry && ry< 141 )
return 3;
else
return 0;
}

Click event on EditText's drawableRight not working properly?

I need to open phone's contact book on the click of EditText's drawableRight. Click event on drawableRight is working fine But the problem is, when I click/touch on anywhere on EditText it is also execute click event and open contact list.
I take help for manage click event on drawableRight from here Please check this link.
I don't want to open contact list when I click on EditText, I only want to open it when I click drawableRight (image). So how solve this problem?
Here is my code:
EditText mobile_number;
mobile_number = (EditText)view.findViewById(R.id.mobile_number1);
mobile_number.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
final int DRAWABLE_LEFT = 0;
final int DRAWABLE_TOP = 1;
final int DRAWABLE_RIGHT = 2;
final int DRAWABLE_BOTTOM = 3;
if(event.getAction()==MotionEvent.ACTION_UP){
if(event.getRawX()>=(mobile_number.getRight()-mobile_number.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width()));
{
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent,PICK_CONTACT);
return true;
}
}
return true;
}
});
Here is my layout code:
<LinearLayout
android:layout_width="fill_parent"
android:id="#+id/linearlayout_two1"
android:layout_below="#+id/linearlayout_one1"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_marginTop="20dp"
android:orientation="vertical"
>
<EditText
android:layout_width="300dp"
android:hint="Enter Your Mobile Number"
android:textSize="15sp"
android:id="#+id/mobile_number1"
android:paddingLeft="30dp"
android:layout_height="wrap_content"
android:drawableRight="#drawable/editbox_icon"
/>
</LinearLayout>
Instead of using getRawX(), try replacing that line with
if (event.getX() >= (mobile_number.getWidth() - mobile_number
.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width())) {
EDIT: I believe View.getRight() returns the position of the right edge of the View relative to its parent, while TouchEvent.getRawX() returns the absolute X position on the screen.
EDIT AGAIN TO DEMONSTRATE MY POINT:
MainActivity.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
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"
tools:context="com.meremammal.www.edittextdrawable.MainActivity">
<!-- This layout is only here to demonstrate a situation that breaks the usage of getRawX() -->
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true">
<EditText
android:id="#+id/edit_text"
android:layout_width="400dp"
android:layout_height="wrap_content"
android:text="Hello World!"
android:drawableRight="#android:drawable/ic_input_add"/>
</RelativeLayout>
</RelativeLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
EditText mEditText;
Context mContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
mEditText = (EditText) findViewById(R.id.edit_text);
mEditText.setOnTouchListener(new View.OnTouchListener() {
private float touchX = 0;
#Override
public boolean onTouch(View v, MotionEvent event) {
int drawableLeft = mEditText.getRight() - mEditText
.getCompoundDrawables()[2].getBounds().width();
// This detects the location of touch on ACTION_DOWN, but because it is
// using getRawX() and getRight() and the EditText's parent is not at the
// left of the screen, it will respond when clicked in the middle of the
// EditText. Instead, use getX() and EditText.getWidth()
if (event.getAction() == MotionEvent.ACTION_DOWN && event.getRawX() >= drawableLeft) {
touchX = event.getRawX();
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP && touchX >= drawableLeft) {
Toast.makeText(mContext, "Clicked Button", Toast.LENGTH_SHORT).show();
touchX = 0;
return true;
} else {
return mEditText.onTouchEvent(event);
}
}
});
}
}
You don't have access to the right image as far my knowledge, unless you create custom EditText class. I suggest to use a RelativeLayout, with one editText and one imageView, and set OnClickListener over the image view as below:
<RelativeLayout
android:id="#+id/rlSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:drawable/edit_text"
android:padding="5dip" >
<EditText
android:id="#+id/txtSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="#+id/imgSearch"
android:background="#00000000"
android:ems="10"/>
<ImageView
android:id="#+id/imgSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="#drawable/btnsearch" />
</RelativeLayout>
Make a Linear layout with horizontal orientation and add a edit-text and image-view with proper weight..
Then Give on click for each item separately.....
Just chage the last return to false. Also you have to remove the comma ; at the end of if statement.

Unable to draw line over gridview elements properly through textview cells in Android

I would like to implement Word Search app. As part of implementation i have come across canvas and drawing line over grid view cells( letters that form the word) to indicate that user is touching finger over letters to form the word.
I have succeeded partially as of now i can draw a line over letters of grid view but the line is not through center of views of grid View.
Please can anyone assist me with your valuable suggestions .
Have a glance on below screen shot to get a clear idea.
Edited: I'm posting code to get an idea of how I'm implementing it.
xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#fff" >
<RelativeLayout
android:id="#+id/topbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#A9E2F3" >
<LinearLayout
android:id="#+id/topbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#336699"
android:orientation="horizontal" >
<Button
android:id="#+id/btn_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pause" />
<Chronometer
android:id="#+id/chronometer1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Chronometer" />
<TextView
android:id="#+id/counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="20sp"
android:typeface="serif" />
</LinearLayout>
</RelativeLayout>
<FrameLayout
android:id="#+id/gridFrame"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/wTable"
android:layout_below="#+id/textdisplay" >
<GridView
android:id="#+id/grid"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#E7E8E9"
android:fitsSystemWindows="true"
android:gravity="center"
android:horizontalSpacing="10sp"
android:numColumns="10"
android:padding="1dp"
android:stretchMode="columnWidth"
android:verticalSpacing="10sp" >
</GridView>
</FrameLayout>
<GridView
android:id="#+id/wTable"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#fff"
android:numColumns="3"
android:orientation="vertical" />
</RelativeLayout>
The paint is drawing over frame layout which contains grid view. Grid view elements are printed through custom text view file.
To draw a line i have used LineView.java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.View;
public class LineView extends View {
public static final float LINE_WIDTH = 30.0f;
public Paint paint = new Paint();
protected Context context;
public float startingX, startingY, endingX, endingY;
public LineView(Context context) {
super(context);
this.context = context;
paint.setColor(Color.parseColor("#2E9AFE"));
paint.setStrokeWidth(LINE_WIDTH);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setDither(true);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
paint.setAlpha(90);
}
public void setPoints(float startX, float startY, float endX, float endY) {
startingX = startX;
startingY = startY;
endingX = endX;
endingY = endY;
invalidate();
}
#Override
public void onDraw(Canvas canvas) {
Log.e("LINEVIEW", "startingX" + startingX + " startingY:" + startingY);
Log.e("LINEVIEW", "endingX" + endingX + " endingY:" + endingY);
// canvas.drawLine(startingX, startingY, endingX, endingY, paint);
canvas.drawLine(startingX, startingY, endingX, endingY, paint);
}
}
Main Activity where logic is implemented:
Written only the required logic here.
newGrid = (GridView) findViewById(R.id.grid);
newGrid.setAdapter(new FormTheGridLetters());
newGrid.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// if (mp.isPlaying()) {
// mp.stop();
// }
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
// data
PaintViewHolder newPaint = new PaintViewHolder();
newPaint.DrawLine = new LineView(WordSearchActivity.this);
gridFrame.addView(newPaint.DrawLine);
buildWord = new StringBuilder();
int x = (int) event.getX();
int y = (int) event.getY();
// test = new LineView(WordSearchActivity.this);
int position = newGrid.pointToPosition(x, y);
Point one,
two;
if (position != GridView.INVALID_POSITION) {
v.getParent().requestDisallowInterceptTouchEvent(true);
cellView = (TextView) newGrid.getChildAt(position);
String a = cellView.getText().toString();
// Log.v(">>>>><<<<<<<????????", a.toString());
switch (action) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
// Checking the list for formed word ;
//if found that is painted
for (int i1 = 0; i1 < Ans.size(); i1++)
{
if (formedWord.equals(Ans.get(i1)))
{
answerAdapter.notifyDataSetChanged();
newPaint.DrawLine.setPoints(startX, startY, x, y);
// Painted the letters by passing starting and ending points
}
}
break;
}
} else {
if (mSelecting) {
mSelecting = false;
}
}
break;
case MotionEvent.ACTION_CANCEL:
mSelecting = false;
break;
}
return true;
}
});
I don't know if you fix the issue but I will answer anyway for the people that may have these kind of problems. After you recieve the valid position, you can get the center of the view and you can set these values as beginning of the draw.
Like this:
if (position != GridView.INVALID_POSITION) {
MyList.add(position);
v.getParent().requestDisallowInterceptTouchEvent(true);
TextView cellView = (TextView) gridView.getChildAt(position);
centreX = cellView.getX() + cellView.getWidth() / 2;
centreY = cellView.getY() + cellView.getHeight() / 2;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
newPaint.DrawLine.touch_start(x, y,centreX,centreY);
I have tried this code and it is working. I don't think that you need anymore but I have joined this site recently so maybe it will help other people. I can post more code if you want but
newPaint.DrawLine.touch_start(x, y,centreX,centreY);
is the trick for that issue.
Hope this helps.

OntouchListener drag across buttons

I am developing a piano app for android. I am trying to implement OnTouchListener for all the 8 buttons that I have in my activity. So, when the user drags or swipes his finger I want all the buttons to play the sound. I think the picture below explains it better.
See? When the user will place his hand on the first button and then drag till the last button, I want all the 8 buttons to play the song. But I am not able to achieve it. The below java code works only for the first button but the rest of the 7 buttons don't get pressed.
Here it is:
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(v.getID())
{
case(R.id.btn1):
//play button 1 sound
break;
case(R.id.btn2):
//play button 2 sound
break;
case(R.id.btn3):
//play button 3 sound
break;
case(R.id.btn4):
//play button 4 sound
break;
case(R.id.btn5):
//play button 1 sound
break;
case(R.id.btn6):
//play button 6 sound
break;
case(R.id.btn7):
//play button 7 sound
break;
case(R.id.btn8):
//play button 8 sound
break;
}
return true;
}
I have already seen this question and this as well but couldn't find an answer there.
Please help me out. Thank you for you time!
You should implement onTouchListner on the layout which contains the piano buttons
The idea is to get all piano buttons positions on the screen (x , y) after render them.
then get touch position by using getX() and getY() methods.
At this point you can handle it by checking if the touch x and y is between the view start and
end x and y, then play the sound of the view.
At this example i'am using soundpool and pitch to play different sounds (i know that it's not the perfect way), and i'm also working on x factor only because i'm using piano white keys only.
import android.app.Activity;
import android.media.*;
import android.os.Bundle;
import android.view.*;
import android.widget.*;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity
{
//The layout that holds the piano keys.
LinearLayout pianoKeysContainer;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
pianoKeysContainer = (LinearLayout) findViewById(R.id.key_container);
pianoKeysContainer.setOnTouchListener(onYourViewTouchListener);
}
//Here we load the view positions after render it and fill the array with the positions
private List<Integer> positionsLeft_whiteKeys = new ArrayList<Integer>();
private List<Integer> positionsRight_whiteKeys = new ArrayList<Integer>();
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
for (int i = 0; i < pianoKeysContainer.getChildCount(); i++)
{
//positionsLeft_whiteKeys holds the start x of each view.
positionsLeft_whiteKeys.add(pianoKeysContainer.getChildAt(i).getLeft());
//positionsRight_whiteKeys holds the end x of each view.
positionsRight_whiteKeys.add(pianoKeysContainer.getChildAt(i).getRight());
}
}
public View.OnTouchListener onYourViewTouchListener = new View.OnTouchListener()
{
float positionX;
FrameLayout pianoKey;
FrameLayout lastPlayedKey;
ArrayList<FrameLayout> pressedKeys = new ArrayList<FrameLayout>();
#Override
public boolean onTouch(View view, MotionEvent motionEvent)
{
positionX = motionEvent.getX();
float pitch;
//Looping on the child of the layout which contains the piano keys
for (int x = 0; x < ((LinearLayout) view).getChildCount(); x++)
{
// Calculating the pitch to get good chords
pitch = (float) Math.pow(Math.pow(2.0, 1 / 12.0), (float) x);
pianoKey = (FrameLayout) ((LinearLayout) view).getChildAt(x);
if (positionsLeft_whiteKeys.size() >= 0 && positionsRight_whiteKeys.size() >= 0)
{
if (positionX > positionsLeft_whiteKeys.get(x) && positionX < positionsRight_whiteKeys.get(x))
{
pianoKey = (FrameLayout) ((LinearLayout) view).getChildAt(x);
if (pianoKey != null)
{
pianoKey.setBackgroundResource(R.drawable.piano_key_pressed);
pressedKeys.add(pianoKey);
}
if (lastPlayedKey != pianoKey)
playKey(pitch);
lastPlayedKey = pianoKey;
break;
}
if (lastPlayedKey != null)
{
pianoKey.setBackgroundResource(R.drawable.piano_key);
lastPlayedKey.setBackgroundResource(R.drawable.piano_key);
}
}
}
if (motionEvent.getAction() == MotionEvent.ACTION_UP)
{
lastPlayedKey = null;
for (FrameLayout pressedKey : pressedKeys)
{
pressedKey.setBackgroundResource(R.drawable.piano_key);
}
}
return false;
}
};
//This is sound play method
SoundPool sp = new SoundPool(1, AudioManager.STREAM_MUSIC, 1);
public void playKey(final float pitch)
{
//here you should store your piano sound at res/raw then load it
sp.load(this, R.raw.piano, 1);
sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener()
{
#Override
public void onLoadComplete(SoundPool soundPool, int i, int i2)
{
soundPool.play(i, 0.99f, 0.99f, 1, 0, pitch);
}
});
}
}
And this is the xml file (main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:id="#+id/key_container">
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"
/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
</LinearLayout>
</LinearLayout>
Note: the only thing you should do to complete the example is to put
you piano key image (pressed and not pressed) and put the piano sound
at res/raw

Clickable items inside an EditText

The problem:
To make a long story short, I would like to insert a custom clickable Drawable (or something that looks like a little button and acts like a single character) inside an EditText.
Research:
I've read some documentation as well as related questions and I almost achieved the result I want (see "Code" section). It's a little bit tricky, but I wasn't able to find another way out. I'm using Html.fromHtml(source, imageGetter, tagHandler) to insert the drawable I need with a link and then implementing a custom LinkMovementMethod to handle clicks on it.
But there are some things I would like to avoid:
If there are no text after my drawable, it gets clicked even if I click anywhere right to it. So I'm not able to place a cursor next to it without moving it manually.
On some devices the cursor appears at the very beginning of EditText every time I perform a click, except cases when I click drawable.
Code:
Inserting drawable with a link and setting the custom LinkMovementMethod:
Html.ImageGetter imgGetter = new Html.ImageGetter() {
#Override
public Drawable getDrawable(String source) {
Drawable drawable = getResources().getDrawable(R.drawable.blip_icon_read);
//Making it as small as a character
drawable.setBounds(0, 0, (int)getTextSize(), (int)getTextSize());
return drawable;
}
};
String buttonSrc = "<a href='button://" + "somedata" + "'><img src=/></a>";
myEditText.append(Html.fromHtml(buttonSrc, imgGetter, null));
myEditText.setMovementMethod(MyLinkMovementMethod.getInstance(context));
Custom LinkMovementMethod:
public class MyLinkMovementMethod extends LinkMovementMethod {
private static Context movementContext;
private static MyLinkMovementMethod linkMovementMethod = new MyLinkMovementMethod();
public boolean onTouchEvent(android.widget.TextView widget, android.text.Spannable buffer, android.view.MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
URLSpan[] link = buffer.getSpans(off, off, URLSpan.class);
if (link.length != 0) {
URI uri;
try {
uri = new URI(link[0].getURL());
} catch (URISyntaxException e) {
e.printStackTrace();
return true;
}
if (uri.getScheme().equals("button")) {
//Doing stuff here
}
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
public static android.text.method.MovementMethod getInstance(Context c) {
movementContext = c;
return linkMovementMethod;
}
}
Layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="#+id/my_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:textColor="#android:color/black"
android:scrollbars="vertical"
android:textCursorDrawable="#null"
android:gravity="top" >
</EditText>
</LinearLayout>
Questions:
Is there any way to avoid things I described in the end of "Research" section using this approach?
Is there another approach I should use?
Will be glad to read advices or any ideas. Thank you.
this seems to work (unless i dont really understand your idea)
public class MyMovementMethod extends ArrowKeyMovementMethod {
#Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
MyClickableSpan[] link = buffer.getSpans(off, off, MyClickableSpan.class);
if (link.length != 0 && off != buffer.length()) {
link[0].doSomething();
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
}
class MyClickableSpan extends ImageSpan {
public MyClickableSpan(Bitmap b) {
super(b);
}
public void doSomething() {
Log.d(TAG, "doSomething ***********************************************");
}
}
to test it add the following in Activity.onCreate:
LinearLayout ll = new LinearLayout(this);
EditText et = new EditText(this);
SpannableStringBuilder b = new SpannableStringBuilder();
b.append("Attach the specified markup object to the ");
int start = b.length();
b.append("x");
int end = b.length();
b.append(" range start end of the text, or move the object to that range if it was...");
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
b.setSpan(new MyClickableSpan(bitmap), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
et.setText(b);
et.setMovementMethod(new MyMovementMethod());
ll.addView(et);
setContentView(ll);
just use a ScrollView as parentView will help you.
Like this
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="45dp"
android:layout_below="#id/header_container"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/title"
android:hint="输入标题"
android:layout_marginStart="15dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginEnd="15dp"
android:inputType="text"
android:textSize="22sp"
android:singleLine="true"
android:textCursorDrawable="#color/cursor_white"
android:background="#drawable/bg_edittext_title_white"
android:padding="5dp"
>
</EditText>
<EditText
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#null"
android:gravity="start|top"
android:layout_marginLeft="15dp"
android:layout_marginStart="15dp"
android:layout_marginRight="15dp"
android:layout_marginEnd="15dp"
android:layout_marginTop="10dp"
android:inputType="textMultiLine"
android:minHeight="220dp"
android:singleLine="false"
android:textCursorDrawable="#color/cursor_white"
android:hint="输入内容"
android:padding="5dp"
/>
</LinearLayout>
</ScrollView>

Categories

Resources