I've just started programming for Android. I've searched for my problem a lot, but the advises didn't help me. I want the same images appear on screen in the touch coordinates. That's what I've done:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View main_view = (View)findViewById(R.id.main_view);
main_view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView image = new ImageView(getApplicationContext());
//ImageView image = (ImageView)findViewById(R.id.broken);
image.setImageResource(R.drawable.broken);
image.setX(event.getX() + image.getWidth() / 2);
image.setY(event.getY() - image.getHeight() / 2);
LinearLayout top_layout = (LinearLayout) findViewById(R.id.top_layout);
LayoutParams p = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
image.setLayoutParams(p);
top_layout.addView(image);
return true;
}
});
}
Everything seems right to me, but when touching the screen, nothing happens. Where is the obvious mistake I've made? Thanks in advance.
You can't do that in a LinearLayout.
Let's use a FrameLayout instead.
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/framelayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
MainActivity.java
public class MainActivity extends Activity {
private FrameLayout mLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLayout = (FrameLayout) findViewById(R.id.framelayout);
mLayout.setOnTouchListener(mListener);
}
private OnTouchListener mListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_UP:
// decode the resource to get width and height
Options opts = new Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher, opts);
int imageWidth = opts.outWidth;
int imageHeight = opts.outHeight;
// set the imageview's top and left margins
FrameLayout.LayoutParams lp = new LayoutParams(imageWidth, imageHeight);
lp.leftMargin = (int) (event.getX() - (imageWidth / 2));
lp.topMargin = (int) (event.getY() - (imageHeight / 2));
ImageView image = new ImageView(MainActivity.this);
image.setImageResource(R.drawable.ic_launcher);
mLayout.addView(image, lp);
return false;
}
return false;
}
};
}
setX and setY don't set the images position. It basically scrolls the image in place. The position is controlled by its parent view. Since its parent is a linear layout, it will always be placed below or to the right of the thing above it in the layout. If you want to place it somewhere exactly, you need to put it in a parent that supports that, such as the deprecated AbsoluteLayout.
Related
Here is the problem I am facing. On a empty relative layout, when touched textview is instantiated at the touched x y position. I got this far correct, but the problem is that when I touch on the empty space near already instantiated view, previous view and currently placed views are overlapped. I tried by the getting the child views of the layout and checking the current view and already placed view using rect data that if they intersect. How to solve this problem?
Here is the code:
public class MainActivity extends AppCompatActivity
{
private int id = 0;
private RelativeLayout root;
private RelativeLayout.LayoutParams params;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_designer);
root = (RelativeLayout) findViewById(R.id.rootlayout);
root.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
instantiateView(v, event);
break;
}
return true;
}
});
}
private void instantiateView(View v, MotionEvent event)
{
int x = (int) event.getX();
int y = (int) event.getY();
TextView bt = new TextView(DesignerActivity.this);
bt.setText("1");
bt.setId(++id);
bt.setBackgroundColor(Color.BLACK);
bt.setTextColor(Color.WHITE);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
showDialog();
}
});
params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(x, y, 0, 0);
bt.setLayoutParams(params);
//((ViewGroup) v).addView(bt);
if(root.getChildCount() <= 0)
{
((ViewGroup) v).addView(bt);
}
else
{
for (int i = 0; i < root.getChildCount(); i++)
{
if (!checkCollision(bt, root.getChildAt(i)))
{
if(bt != root.getChildAt(i))
{
((ViewGroup) v).addView(bt);
}
}
}
}
}
private void showDialog()
{
final Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.dialog_layout);
Button editBtn = (Button) dialog.findViewById(R.id.button1);
Button deleteBtn = (Button) dialog.findViewById(R.id.button2);
editBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
dialog.dismiss();
}
});
deleteBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
dialog.dismiss();
}
});
dialog.show();
}
private boolean checkCollision(View v1, View v2)
{
Rect r1 = new Rect(v1.getLeft(), v1.getTop(), v1.getRight(), v1.getBottom());
Rect r2 = new Rect(v2.getLeft(), v2.getTop(), v2.getRight(), v2.getBottom());
return r1.intersect(r2);
}
}
You are using Relative Layout that's why your Textviews are overlapping.
If you don't want the overlapping and want to place it next or somewhere else to the overlapped view , it is your decision. Just check if they intersect and take appropriate decision based on your requirement.
Below line is the problem in your code.
Rect r1 = new Rect(v1.getLeft(), v1.getTop(), v1.getRight(), v1.getBottom());
You set the params' Margin does not mean that you will get desired left,top,right, bottom values.You will get these values right after the inflation of your view hierarchy.
You can use this function:
private boolean checkCollision(View v1, View v2)
{
int leftMargin = ((RelativeLayout.LayoutParams) v1.getLayoutParams()).leftMargin;
int topMargin = ((RelativeLayout.LayoutParams) v1.getLayoutParams()).topMargin;
Rect r1 = new Rect(root.getPaddingLeft() + leftMargin, root.getPaddingTop() + topMargin,
root.getPaddingLeft() + leftMargin + v2.getWidth(), root.getPaddingTop() + topMargin + v2.getHeight());
Rect r2 = new Rect(v2.getLeft(), v2.getTop(), v2.getRight(), v2.getBottom());
return r1.intersect(r2);
}
After that use
params.addRule(); according to your requirement where you want to place your overlapping view.
As a example,have to draw a layout of images.
I inflated an ImageView into a layout. When I swipe on the screen I need to change the color of the each circle to green. How should I do it. I tried with gesture detector, but I can't get what I need.
and this is my code.. I create this view by inflating an image view..
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(1024);
setContentView(R.layout.test);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
height = displaymetrics.heightPixels;
width = displaymetrics.widthPixels;
count = width/30;
totalCircles = count * (height/30);
horizontalSpace = width%30;
verticalSpace = height%30;
mRelativeLayout = (RelativeLayout)findViewById(R.id.fl);
mRelativeLayout.setPadding(horizontalSpace/2, verticalSpace/2, horizontalSpace/2, verticalSpace/2);
for(int i=1;i<totalCircles+1;i++){
myButton = new ImageView(this);
myButton.setId(i);
myButton.setImageResource(R.drawable.circle_grey);
LayoutParams lp = new LayoutParams(0,0);
if(i%count != 1){
lp.addRule(RelativeLayout.RIGHT_OF, imgViews.get(i-2).getId());
if(imView != null){
lp.addRule(RelativeLayout.BELOW, imView.getId());
}
if(i%count == 0){
imView = myButton;
}
}else{
if(imView != null){
lp.addRule(RelativeLayout.BELOW, imView.getId());
}
}
mRelativeLayout.addView(myButton,lp);
myButton.getLayoutParams().width = 30;
myButton.getLayoutParams().height = 30;
imgViews.add(myButton);
myButton.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
System.out.println("Inside touch listener");
ImageView imV = (ImageView)v;
imV.setImageResource(R.drawable.circle_green);
}
return false;
}
});
}
}
Jack K Fouani's answer is partially correct. Instead of imagView.onTouch you need to use gridview.onTouch.
Please check this sample.
gv.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
float currentXPosition = event.getX();
float currentYPosition = event.getY();
int position = gv.pointToPosition((int)currentXPosition, (int) currentYPosition);
//using the position obtained you can change the imageview color.
}
return true;
}
});
Instead of inflating one ImageView. You should fill a GridView where every GridCell contains a circle image. Now
set the OnTouchEvent of those Gridcells to change the ImageView within the GridCell.
my advice is to use GrideView with adapter , inside the adapter you will have position for each imagView the position allow you to check if image is touched or not depending on that you can change ImageView color to white or green
I'm basically trying to achieve drag&drop feature..
What i'm trying is that i provides sequence of images on the screen, if i click on any image available in images row that will be added to the Mains screen. But i'm getting problem that when i add new view into the Main Screen then all the other views also moved to top left corner.
Can you please tell me what is the problem...? Or kindly suggest me a tutorial or link where i can find solution.... or how to achieve this ?
I'm using Framelayout, So that i also achieve images overlapping...
This is the class in which all code is working:
public class drag extends Activity implements OnClickListener, OnTouchListener
{
ImageView img1;
Button btn,btn2;
FrameLayout layout;
LayoutParams params;
ImageView im , im2, im3 ,im4;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
layout = (FrameLayout) findViewById(R.id.vg);
layout.setDrawingCacheEnabled(true);
im = (ImageView)findViewById(R.id.img1);
im.setDrawingCacheEnabled(true);
im.setOnTouchListener(this);
im.setOnClickListener(this);
btn = (Button)findViewById(R.id.btn1);
btn.setDrawingCacheEnabled(true);
btn.setOnClickListener(this);
btn.setOnTouchListener(this);
btn2 = (Button)findViewById(R.id.btn2);
btn2.setDrawingCacheEnabled(true);
btn2.setOnClickListener(this);
btn2.setOnTouchListener(this);
params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
btn.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
im2 = new ImageView(drag.this);
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.image);
im2.setImageBitmap(bm);
im2.setOnTouchListener(drag.this);
im2.setOnClickListener(drag.this);
layout.addView(im2, params);
}
});
btn2.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.image);
saveImage(bm);
}
});
}
public void saveImage(Bitmap myBitmap)
{
MediaStore.Images.Media.insertImage(getContentResolver(), myBitmap, "mmsImage" , "mmsimage");
}
int l, t, r, b;
int oldLeft, oldTop;
PointF p, curr;
#Override
public boolean onTouch(View view, MotionEvent me)
{
if (me.getAction() == MotionEvent.ACTION_DOWN)
{
//status = START_DRAGGING;
Log.i("status"," AAA dOWN");
img1 = new ImageView(this);
view.setDrawingCacheEnabled(true);
Bitmap mmsImage = Bitmap.createBitmap(view.getDrawingCache());
img1.setImageBitmap(mmsImage);
img1.setOnTouchListener(drag.this);
img1.setOnClickListener(drag.this);
oldLeft = (int)view.getLeft();
oldTop = (int)view.getTop();
p = new PointF(me.getRawX(), me.getRawY());
}
if (me.getAction() == MotionEvent.ACTION_MOVE)
{
Log.i("status"," AAA draging");
int xDiff = (int)(me.getRawX() - p.x);
int yDiff = (int)(me.getRawY() - p.y);
p.x = me.getRawX();
p.y = me.getRawY();
l = view.getLeft();
t = view.getTop();
r = view.getRight();
b = view.getBottom();
view.layout(l + xDiff, t + yDiff , r + xDiff, b + yDiff);
}
if (me.getAction() == MotionEvent.ACTION_UP)
{
Log.i("status"," AAA UP");
//captureUserMove(view);
}
return false;
}
}
Here is the XML :
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/vg"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#android:color/white" >
<ImageView
android:id="#+id/img1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="#drawable/ic_launcher" />
<Button
android:id="#+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<Button
android:id="#+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
</FrameLayout>
You set params, but don't specify how to position the added view. Try this:
In onCreate()
params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.LEFT | Gravity.TOP; // you need this for margins to work
In the click listener:
// your x and y where you want the new view
params.leftMargin = x;
params.topMargin = y;
Putting
params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
inside
#Override
public void onClick(View v)
{
}
will work.
I have a fairly simply Fragment that adds a handful of colored ImageViews to a RelativeLayout. There are more images than can fit on screen, so I implemented some custom scrolling.
However, When I scroll around, I see that there is an approximately 90dp white border overlapping part of the content right where the edges of the screen are before I scroll.
It is obvious that the ImageViews are still being created and drawn properly, but they are being covered up.
How do I get rid of this?
I have tried:
Changing both the RelativeLayout and FrameLayout to WRAP_CONTENT, FILL_PARENT, MATCH_PARENT, and a few combinations of those.
Setting the padding and margins of both layouts to 0dp.
Example:
Fragment:
public class MyFrag extends Fragment implements OnTouchListener {
int currentX;
int currentY;
RelativeLayout container;
final int[] colors = {Color.BLACK, Color.RED, Color.BLUE};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup fragContainer, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_myfrag, null);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
container = (RelativeLayout) getView().findViewById(R.id.container);
container.setOnTouchListener(this);
// Temp- Add a bunch of images to test scrolling
for(int i=0; i<1500; i+=100) {
for (int j=0; j<1500; j+=100) {
int color = colors[(i+j)%3];
ImageView image = new ImageView(getActivity());
image.setScaleType(ImageView.ScaleType.CENTER);
image.setBackgroundColor(color);
LayoutParams lp = new RelativeLayout.LayoutParams(100, 100);
lp.setMargins(i, j, 0, 0);
image.setLayoutParams(lp);
container.addView(image);
}
}
}
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
currentX = (int) event.getRawX();
currentY = (int) event.getRawY();
break;
}
case MotionEvent.ACTION_MOVE: {
int x2 = (int) event.getRawX();
int y2 = (int) event.getRawY();
container.scrollBy(currentX - x2 , currentY - y2);
currentX = x2;
currentY = y2;
break;
}
case MotionEvent.ACTION_UP: {
break;
}
}
return true;
}
}
XML:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".FloorPlanFrag">
<RelativeLayout
android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
While looking through the RelativeLayout source, I noticed that onMeasure() calls applyHorizontalSizeRules(LayoutParams childParams, int myWidth) and applyVerticalSizeRules(LayoutParams childParams, int myHeight).
In applyHorizontalSizeRules I found that for the myWidth and myHeight params:
// -1 indicated a "soft requirement" in that direction. For example:
// left=10, right=-1 means the view must start at 10, but can go as far as it wants to the right
The myWidth parameter is initialized to -1, and then changed based on the MeasureSpec's mode for onMeasure()'s parameters.
So I created my own View that extends RelativeLayout, and overrode onMeasure() to set the mode to 'unspecified':
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int newWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED);
int newHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED);
super.onMeasure(newWidthSpec, newHeightSpec);
}
Works like a charm!
I am trying to shift the position of a image button when on click. I tried the following but it crashes at "rlOut.addView(imgP, p);" I have no issues when running them in onCreate().
public class Delet3Activity extends Activity {
RelativeLayout rlOut;
ImageButton imbBtn;
EditText et1, et2;
ImageView ivB;
ImageButton imgP;
RelativeLayout.LayoutParams p;
RelativeLayout.LayoutParams params;
int mX, mY;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
et1 = (EditText)findViewById(R.id.et1);
et2 = (EditText)findViewById(R.id.et2);
imbBtn = (ImageButton)findViewById(R.id.imgBtn);
rlOut = (RelativeLayout)findViewById(R.id.rlOut);
imgP = (ImageButton)findViewById(R.id.imgP);
ivB = new ImageView(this);
ivB.setBackgroundColor(Color.RED);
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
width = width/2-62;
height = height/2-62;
p = new RelativeLayout.LayoutParams(62, 62);
imbBtn.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
LayoutParams par = (LayoutParams)imbBtn.getLayoutParams();
if(event.getAction()==MotionEvent.ACTION_DOWN)
{
Log.d("ok","down");
mX = (int) event.getX() - imbBtn.getWidth() / 2;
mY = (int) event.getY() - imbBtn.getHeight() / 2;
et1.setText("mX down: "+String.valueOf(mX));
et2.setText("mY down: "+String.valueOf(mY));
}
else if (event.getAction()==MotionEvent.ACTION_UP)
{
Log.d("ok","up");
rlOut.addView(ivB, params);
p.leftMargin=4;
params.leftMargin = 60;
params.topMargin = 20;
rlOut.addView(imgP, p);
Log.d("ok","p");
}
else if (event.getAction()==MotionEvent.ACTION_MOVE)
{
Log.d("ok","move");
mX = (int) event.getX() - imbBtn.getWidth() / 2;
mY = (int) event.getY() - imbBtn.getHeight() / 2;
et1.setText("mX move: "+String.valueOf(mX));
et2.setText("mY move: "+String.valueOf(mY));
}
return false;
}
});
}
}
OnCreate method is the place where you set the setContentView(R.layout.main). I suppose the variable rlOut stands for RelativeLayout which might be in your main layout. Call the above function within the OnCreate methods after you set the contentView and have initialized the variable rlOut using findViewById. Or if the variable rlOut is in some other layout file then you will have to first inflate that layout using layout inflater and then find the view using findViewById method.
Hope this helps.
EDIT
The following code should probably be the solution you are looking for:
imbBtn.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
LayoutParams par = (LayoutParams)imbBtn.getLayoutParams();
if (event.getAction()==MotionEvent.ACTION_MOVE)
{
Log.d("ok","move");
mX = (int) event.getX() - imbBtn.getWidth() / 2;
mY = (int) event.getY() - imbBtn.getHeight() / 2;
par.leftMargin = imbBtn.getLeft() + mX;
par.topMargin = imbBtn.getTop() + mY;
imbBtn.setLayoutParams(par);
et1.setText("mX move: "+String.valueOf(mX));
et2.setText("mY move: "+String.valueOf(mY));
}
return false;
}
});
MotionEvent.ACTION_MOVE is the only event you need to capture. Hope this solution is helpful to you.