I am extend a SupportMapFragment which contain google map here, I lay my google map on a frameLayout according to How to handle onTouch event for map in Google Map API v2?. Ondraw()method is called , but the problem is rectangle is never been showed, even when I use setWillNotDraw(false); here.
I already got the right position of the rectangle, the only problem is it is not showed. Following is my most part of code:
Add-on:When I remove the google map it works as I expect, actually the rectangle drawed on the background frameLayout, so it will be covered by the map, now the way I solve the question is add a image view as a rectangle and dynamic change its size when touch moving. I have no idea how to draw directly on the top of this viewgroup(framelayout) at the moment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
//stash reference to google map
mGoogleMap = getMap();
//show the location
mGoogleMap.setMyLocationEnabled(true);
mTouchView = new TouchableWrapper(getActivity());
mTouchView.addView(view);
return mTouchView;
}
private class TouchableWrapper extends FrameLayout {
//box is used to illustrate the drawing box, the painter is used to set the color of the box.
private Box mCurrentBox = null;
private Paint mBoxPaint;
public TouchableWrapper(Context context) {
super(context);
mBoxPaint = new Paint();
mBoxPaint.setColor(0xffff0000);
// mBoxPaint.setStrokeMiter(20);
mBoxPaint.setStrokeWidth(8);
this.setWillNotDraw(false);
setWillNotDraw(false);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// decide when the child should hold the motion event.
return true; //always let the relative layout to hold the motion event.
}
#Override
public boolean onTouchEvent(MotionEvent event) {
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mMapIsTouched = true;
mCurrentBox = new Box(curr);//original code for draw Rectangle.
Log.d(TAG, "action.down box is"+mCurrentBox);
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "action_move");
if (mCurrentBox != null) {
mCurrentBox.setmCurrent(curr);
Log.d(TAG, "action.move box is"+mCurrentBox);
this.invalidate(); //TODO
}
break;
case MotionEvent.ACTION_UP:
Log.i(TAG, "action_up");
mMapIsTouched = false;
mCurrentBox = null;
break;
}
return true;
}
#Override
protected void onDraw(Canvas canvas) {
float left = 0;
float right = 0;
float top = 0;
float bottom = 0;
if (mCurrentBox!=null) {
left = Math.min(mCurrentBox.getmOrigin().x, mCurrentBox.getCurrent().x) ;
right = Math.max(mCurrentBox.getmOrigin().x, mCurrentBox.getCurrent().x) ;
top = Math.min(mCurrentBox.getmOrigin().y, mCurrentBox.getCurrent().y) ;
bottom = Math.max(mCurrentBox.getmOrigin().y, mCurrentBox.getCurrent().y) ;
canvas.drawRect(left, top, right, bottom, mBoxPaint);
}
Log.i(TAG, "value is"+left+right+top+bottom);
}
You could wrap the Map in a FrameLayout containing also a Drawable (your rectangle). In that way, once you find where the rectangle shall be, you could hide and show it without having to redraw it.
You can see here for an example.
Related
I have not yet found any way to solve this on stack.
I have a webview in my app. I want to be able to detect when the keyboard is active and when it is not active. It seems as if it cant detect these changes when they happon in a webview.
I want to perform actions on these different states. On iOS its really simple with observers that listens when the keyboard is active. Ref UIKeyboardWillShow/Hide.
Is there any functionality in android that does the same as these observers do in android?
Hopefully the question is well enough explained.
So I struggled with this a week or so and found a lot of material Here is my solution, I really hope that it works for you.
So in my case I have an Activity, and I call a fragment that contains the Webview so it was a lot trickier than I thought.
Basically the issue is that the fragment was missing this line:
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
So it didn't recognized the change of height inside the webview.
Anyways lets get to the code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
//mWebView.postUrl("https://www.google.com/");
final View activityRootView = view;
layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
// This variable was created only for Debug purposes and
// to see the height change when clicking on a field inside mWebView
int screenHeight = activityRootView.getRootView().getHeight();
Log.d("onGlobalLayout", "rect: " + r.toString());
Log.d("onGlobalLayout", "screenHeight: " + screenHeight);
//The difference on the heights from bottom to top and on the root height
int heightDiff = screenHeight - (r.bottom - r.top);
Log.d("onGlobalLayout", "heightDiff: " + heightDiff);
//I suggest to put 250 on resources and retrieve from there using getResources().getInteger() to have better order
float dpx = dpToPx(getActivity(), 250);
if (previousHeightDiff != heightDiff) {
if (heightDiff > dpx) {
isSoftKeyboardPresent = true;
} else {
isSoftKeyboardPresent = false;
}
previousHeightDiff = heightDiff;
}
}
};
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
return view;
}
private static float dpToPx(Context context, float valueInDp) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
Remember to put on your AndroidManifest.xml a setting on the activity set to: android:windowSoftInputMode="adjustResize|stateHidden"
The variables inside the fragment are:
public boolean isSoftKeyboardPresent = false;
private int previousHeightDiff = -1;// this is used to avoid multiple assignments
private ViewTreeObserver.OnGlobalLayoutListener layoutListener = null;
Finally
#Override
public void onPause() {
super.onPause();
final View activityRootView = getActivity().findViewById(R.id.page_content);
activityRootView.getViewTreeObserver().removeOnGlobalLayoutListener(layoutListener);
}
And this should do the trick :) so what do you think?
I have imported a external library to implement a TileView from this library: TileView 2.2.7
I have read all the documentation but I didn't find a method to get the color of the pixel of the touched point.
This is a part of my code, but I think that is not helpful to solve the problem.
public class GetDamages extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final TileView tileView = new TileView(getApplicationContext());
tileView.setSize(1855, 2880);
tileView.setScaleLimits(0, 2);
tileView.setShouldRenderWhilePanning(true);
tileView.addDetailLevel(0.125f, "tiles/auto/125/%d_%d.jpg");
tileView.addDetailLevel(0.250f, "tiles/auto/250/%d_%d.jpg");
tileView.addDetailLevel(0.500f, "tiles/auto/500/%d_%d.jpg");
tileView.addDetailLevel(1.000f, "tiles/auto/1000/%d_%d.jpg");
//Setup OnTouchListener
tileView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int eventAction = motionEvent.getAction();
switch (eventAction) {
case MotionEvent.ACTION_DOWN:
double x = tileView.getCoordinateTranslater().translateAndScaleAbsoluteToRelativeX(tileView.getScrollX() + motionEvent.getX(), tileView.getScale());
double y = tileView.getCoordinateTranslater().translateAndScaleAbsoluteToRelativeY(tileView.getScrollY() + motionEvent.getY(), tileView.getScale());
//HERE I NEED TO GET THE PIXEL COLOR
//addPin(tileView, x, y);
break;
}
return false;
}
});
tileView.defineBounds(0, 0, 1, 1);
tileView.setMarkerAnchorPoints(-0.5f, -1.0f);
tileView.setScale(0.5f);
setContentView(tileView);
}
//Add marker in the map
private void addPin(TileView tileView, double x, double y) {
ImageView imageView = new ImageView(this);
imageView.setImageResource(R.drawable.push_pin);
tileView.addMarker(imageView, x, y, -0.5f, -1.0f);
}
}
I have already tried different solution among which this, but
final Bitmap bitmap = ((BitmapDrawable)tileView.getDrawable()).getBitmap();
because TileView doesn't have getDrawable()...
tileView.getTileCanvasViewGroup().setDrawingCacheEnabled(true);
Bitmap hotspots = Bitmap.createBitmap(tileView.getTileCanvasViewGroup().getDrawingCache());
int touchColor;
if (hotspots == null) {
touchColor = 0;
} else { tileView.getTileCanvasViewGroup().setDrawingCacheEnabled(false);
touchColor = hotspots.getPixel((int)x, (int)y);
}
Log.wtf("Debug", "Pixel Color " + touchColor);
This solution return always the same negative integer
Try tileview.tilemap It's just an idea, but it looks like your trying to reference a piece of a map from a view and not the map itself.
BTW, if you are making a game, I would suggest libgdx. It's has a tile map loader built in and a whole game framework. It's also multiplatform.
https://libgdx.badlogicgames.com/
Yes, and you are making map out of this? Because you may just want to use a tiled map loader.
But anyway, looks like tile map canvas has something to do with bitmap rendering, have you looked at that?
http://moagrius.github.io/TileView/index.html?com/qozix/tileview/TileView.html
I'm trying to drag ImageView to google map and drop it as a marker.
Map is in FrameLayout:
<FrameLayout
android:id="#+id/map_frg"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2">
I've set to this FrameLayout OnDragListener:
private class PinDragListener implements View.OnDragListener {
private GoogleMap map;
public PinDragListener(GoogleMap map) {
this.map = map;
}
#Override
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DROP:
MarkerOptions markerOptions = new MarkerOptions()
.draggable(true)
.anchor(0.0f, 1.0f);
int[] coords = new int[2];
v.getLocationOnScreen(coords);
Projection projection = map.getProjection();
LatLng latLng = projection.fromScreenLocation(new Point(coords[0], coords[1]));
markerOptions.position(latLng);
markerOptions.visible(true);
map.addMarker(markerOptions);
break;
default:
break;
}
return true;
}
}
But when image was dropped somewhere marker placed in the left corner again and again. What can be wrong?
UPDATE:
I've passed dragged view via listener
private class PinTouchListener implements OnTouchListener {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
ClipData data = ClipData.newPlainText("", "");
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
v.startDrag(data, shadowBuilder, v, 0);
dragPinListener.onViewTouched(v);
return true;
} else {
return false;
}
}
}
and I've got such coordinates every time I dropped marker
x = 0 | y = 1234
Lat = 65.96291676309829 | Lng = -18.548969998955727
The OnDragListener.onDrag() method will get called for each specific event that occurs during the drag-and-drag process, passing in a DragEvent to describe the specifics of each event.
Each DragEvent will have one of the following actions:
ACTION_DRAG_LOCATION : Sent to a view between ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED with the current location of the drag inside that view.
・ The location can be obtained with getX() and getY().
How It Works
Here are example of the drag-and-drop functionality, We have created a custom ImageView that implements the OnDragListener interface.
Please refer to the following this link:
http://www.tutorialspoint.com/android/android_drag_and_drop.htm
https://github.com/wada811/Android-View-Drag-And-Drop-Sample/blob/master/app/src/main/java/com/wada811/android_view_drag_and_drop_sample/DragAndDropFrameLayout.java
Hope it helps.
I need to use event.getX() and event.getY() in onDrag method in OnDragListener to retrieve current view screen location.
I created an onTouchEvent to find where the user touches and move my object to that position. what I would like to do is if the user presses up on the screen, the object moves a certain distance straight up. and the same for the other directions. I know that I need a few if statements to do this but I don't know how to do it. does anyone have any advice or know how to do this, thanks
public boolean onTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_DOWN) {
// the new image position became where you touched
x = ev.getX();
y = ev.getY();
// if statement to detect where user presses down
if(){
}
// redraw the image at the new position
Draw.this.invalidate();
}
return true;
}
Try this
public boolean onTouchEvent(MotionEvent ev) {
initialise boolean actionDownFlag = false;
if(ev.getAction() == MotionEvent.ACTION_DOWN) {
// the new image position became where you touched
x = (int) ev.getX();
y = (int) ev.getY();
// if statement to detect where user presses down
if(actionDownFlag){
catcher.moveDown();
}
// redraw the image at the new position
Draw.this.invalidate();
}
return true;
}
public void moveDown(){
posX -= //WhereEver you want to move the position (-5);
}
try this:
layout_counter.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event)
{
if (currentState != State.EDIT_MOVE) return false;
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams();
if (view.getId() != R.id.layout_counter) return false;
switch (event.getAction())
{
case MotionEvent.ACTION_MOVE:
params.topMargin = (int) event.getRawY() - view.getHeight();
params.leftMargin = (int) event.getRawX() - (view.getWidth() / 2);
view.setLayoutParams(params);
break;
case MotionEvent.ACTION_UP:
params.topMargin = (int) event.getRawY() - view.getHeight();
params.leftMargin = (int) event.getRawX() - (view.getWidth() / 2);
view.setLayoutParams(params);
break;
case MotionEvent.ACTION_DOWN:
view.setLayoutParams(params);
break;
}
return true;
}
});
You need to use OnLongClickListener which suits better with drag and drop framework of android:
Observe the following example:
public class MainActivity extends Activity {
private ImageView myImage;
private static final String IMAGEVIEW_TAG = "The Android Logo";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myImage = (ImageView)findViewById(R.id.image);
// Sets the tag
myImage.setTag(IMAGEVIEW_TAG);
// set the listener to the dragging data
myImage.setOnLongClickListener(new MyClickListener());
findViewById(R.id.toplinear).setOnDragListener(new MyDragListener());
findViewById(R.id.bottomlinear).setOnDragListener(new MyDragListener());
}
private final class MyClickListener implements OnLongClickListener {
// called when the item is long-clicked
#Override
public boolean onLongClick(View view) {
// TODO Auto-generated method stub
// create it from the object's tag
ClipData.Item item = new ClipData.Item((CharSequence)view.getTag());
String[] mimeTypes = { ClipDescription.MIMETYPE_TEXT_PLAIN };
ClipData data = new ClipData(view.getTag().toString(), mimeTypes, item);
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag( data, //data to be dragged
shadowBuilder, //drag shadow
view, //local data about the drag and drop operation
0 //no needed flags
);
view.setVisibility(View.INVISIBLE);
return true;
}
}
class MyDragListener implements OnDragListener {
Drawable normalShape = getResources().getDrawable(R.drawable.normal_shape);
Drawable targetShape = getResources().getDrawable(R.drawable.target_shape);
#Override
public boolean onDrag(View v, DragEvent event) {
// Handles each of the expected events
switch (event.getAction()) {
//signal for the start of a drag and drop operation.
case DragEvent.ACTION_DRAG_STARTED:
// do nothing
break;
//the drag point has entered the bounding box of the View
case DragEvent.ACTION_DRAG_ENTERED:
v.setBackground(targetShape); //change the shape of the view
break;
//the user has moved the drag shadow outside the bounding box of the View
case DragEvent.ACTION_DRAG_EXITED:
v.setBackground(normalShape); //change the shape of the view back to normal
break;
//drag shadow has been released,the drag point is within the bounding box of the View
case DragEvent.ACTION_DROP:
// if the view is the bottomlinear, we accept the drag item
if(v == findViewById(R.id.bottomlinear)) {
View view = (View) event.getLocalState();
ViewGroup viewgroup = (ViewGroup) view.getParent();
viewgroup.removeView(view);
//change the text
TextView text = (TextView) v.findViewById(R.id.text);
text.setText("The item is dropped");
LinearLayout containView = (LinearLayout) v;
containView.addView(view);
view.setVisibility(View.VISIBLE);
} else {
View view = (View) event.getLocalState();
view.setVisibility(View.VISIBLE);
Context context = getApplicationContext();
Toast.makeText(context, "You can't drop the image here",
Toast.LENGTH_LONG).show();
break;
}
break;
//the drag and drop operation has concluded.
case DragEvent.ACTION_DRAG_ENDED:
v.setBackground(normalShape); //go back to normal shape
default:
break;
}
return true;
}
}
}
The above code taken from here demonstrates how to drag and drop and how to do something while dragging..
I've used something similar as well.
I'm doing a simulator on Android to simulate the move of our robot(represented by a circle in this case). The circle should move forward, turn right or turn left accordingly when the forward/ right/ left button is clicked.
But when I run this program and click the buttons, the circle didn't move...
In the main activity I have the onClickListener like this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.forward_button).setOnClickListener(mGlobal_OnClickListener);
findViewById(R.id.right_button).setOnClickListener(mGlobal_OnClickListener);
findViewById(R.id.left_button).setOnClickListener(mGlobal_OnClickListener);
}
View.OnClickListener mGlobal_OnClickListener = new View.OnClickListener() {
public void onClick(View v) {
GameView gameView = new GameView(Menu.this);
switch(v.getId()) {
case R.id.forward_button:
gameView.controlRobot(GameView.FORWARD);
break;
case R.id.right_button:
gameView.controlRobot(GameView.RIGHT);
break;
case R.id.left_button:
gameView.controlRobot(GameView.LEFT);
}
}
};
In the GamaView Class which extends View class, I draw a circle like this:
canvas.drawCircle((currentX * cellHeight)+(cellHeight/2), //x of center
(currentY * cellHeight)+(cellHeight/2), //y of center
(cellHeight*3*0.45f), //radius
robot);
Also In the GameView Class I have this controlRobot method to move this circle:
(The move/ rotate methods are correct. I have tested them)
public boolean controlRobot(int keyCode) {
boolean moved = false;
boolean rotated = false;
//move(0):move up on the map
//move(3):move right on the map
//move(6):move down on the map
//move(9):move left on the map
//forward
switch (keyCode) {
case FORWARD:
if(rotate_count%12==0)
moved = maze.move(0);
if(rotate_count%12==3)
moved = maze.move(3);
if(rotate_count%12==6)
moved = maze.move(6);
if(rotate_count%12==9)
moved = maze.move(9);
break;
case RIGHT:
rotated = maze.rotate(Maze.RIGHT,rotate_count);
if(rotated)
rotate_count+=3;
break;
case LEFT:
rotated = maze.rotate(Maze.LEFT,rotate_count);
if(rotated)
rotate_count-=3;
break;
}
if(moved||rotated) {
//the ball was moved so we'll redraw the view
invalidate();
}
return true;
}
when your reference the GameView in your onclick like this
GameView gameView = new GameView(Menu.this);
that is not the GameView in your layout file
R.layout.main
try referencing the GameView in your onClick like you did your buttons
findViewById(R.id.forward_button)
except with the R.id for the GameView in your layout file