I am looking for a solution to have larger bounds for selector of an Android view.
Imagine that View is a rectangle view. When user click on the view touch feedback that will be shown is a circle pretty larger than view bounds.
Do you know a good approach to build such an idea?
There is no way how to do that in view's bounds.(I think ). You can implement it by making visual action on parent background view.
ImageButton im = (ImageButton) findViewById(R.id.ur_btn);
im.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
float x = im.getX();
float y = im.getY();
}
});
}
private void addCircleBehindRectangle(int x, int y){
RelativeLayout parent = (RelativeLayout) findViewById(R.id.my_relative_layout);
ImageView iv = new ImageView(this);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(x, y);
//optional margin l/r
params.leftMargin = 50;
params.topMargin = 60;
parent.addView(iv, params);
}
I hope it helps a little bit. Good luck
If you want to show a view outside of its clipping area, you need to enable this in its parent container (any layout which derives from ViewGroup):
ViewGroup.clipChildren
Another way is increase/decrease paddings of the clicked view itself.
Related
As you can see in the image, I can select the view and 3 ImageViews get added using "_root.addView(dragIcon);".
My problem is that the view is a simple view and not a ViewGroup , which means that in this picture i had to add the 3 images to the RelativeView Background "root.addView(dragIcon);" Instead of to the Green rectangle view shown in the image.
I'm pretty sure i can't change the View to a ViewGroup becuase a lot of methods (ex. onTouch) require a "View". I've tried casting the View to a ViewGroup "((ViewGroup) view).addView(dragIcon);" but that did't work.
You can make multiple Views in the app and drag them around, so I need to make the 3 images children to the specific parent View.
Any suggestions are appreciated, thanks!
Here is the part of the code that's relevant to this question...
_root = (ViewGroup)findViewById(R.id.root); //This is the background
_view = new View(this); //This is the View (Green in the Image)
private void selectView(final View view) {
view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(final View view, final MotionEvent event) {
view.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
ImageView dragIcon, sizeIconTop, sizeIconBottom;
if (view.getTag(R.string.viewSelected) != "1") {
view.setBackgroundColor(0xFF00AA00);
view.setTag(R.string.viewSelected, "1");
double Ypos = view.getTranslationY() - view.getHeight() / 2;
// Set draggable (6*3 grid on the right)
dragIcon = new ImageView(MainActivity.this);
dragIcon.setImageResource(R.drawable.drabicon);
RelativeLayout.LayoutParams imgParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
imgParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
imgParams.setMargins(0,0,30,0);
dragIcon.setLayoutParams(imgParams);
dragIcon.setTranslationY((float) Ypos + 70 + view.getHeight() / 2);
_root.addView(dragIcon); //Need to change from _root.addView to view.addView
// Set size top (White line at the top)
sizeIconTop = new ImageView(MainActivity.this);
sizeIconTop.setImageResource(R.drawable.resize);
RelativeLayout.LayoutParams stImgParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
stImgParams.setMargins(0,0,30,0);
stImgParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
sizeIconTop.setLayoutParams(stImgParams);
sizeIconTop.setTranslationY((float) Ypos + 99);
_root.addView(sizeIconTop); //Need to change from _root.addView to view.addView
// Set size bottom (White line at the bottom)
sizeIconBottom = new ImageView(MainActivity.this);
sizeIconBottom.setImageResource(R.drawable.resize);
RelativeLayout.LayoutParams sbImgParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
sbImgParams.setMargins(0,0,30,0);
sbImgParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
sizeIconBottom.setLayoutParams(sbImgParams);
sizeIconBottom.setTranslationY((float) Ypos + 93 + view.getHeight());
_root.addView(sizeIconBottom); //Need to change from _root.addView to view.addView
} else { //Ignore this part
//((ViewGroup) view).removeView(dragIcon);
//((ViewGroup) view).removeView(sizeIconTop);
//((ViewGroup) view).removeView(sizeIconBottom);
view.setBackgroundColor(0xFF00FF00);
view.setTag(R.string.viewSelected, "0");
}
}
});
Even though the question is a bit confusing, after analysing your code I figured out what you wanted to do.
Unfortunately, you have to choose whether to use a View (and not being able to attach the ImageViews) or using a ViewGroup (and handling the events yourself).
Since your View is a View, and your 3 ImageViews are also Views (means they are at the same level of usage), you can not add the last 3 to the first.
The rule is : You can add ViewGroups and Views to a ViewGroup, but you can not add Views or ViewGroups to a View. Views are supposed to be the elementary block of Android design.
void addView (View child)
Adds a child view. If no layout parameters
are already set on the child, the default parameters for this
ViewGroup are set on the child.
In my opinion, I would make View a ViewGroup and take care of the TouchEvents by myself.
Check this documentation/code regarding TouchEvents on ViewGroups
Let me know of your progress. Will be glad to help you.
Regards,
I have a view that is added dynamically. Sometimes, the view is only partly visible since its bottom is off the screen. In this case, I want to move the view up. However, I don't know how to detect whether it is offscreen or not and by how much.
Edit: the context for this problem is that I have an edittext that I want to show a custom soft keyboard right next to it. Here is the code that I use to move the custom keyboard.
public void moveKeyboardNextToView(View view) {
int[] location = new int[]{0, 0};
view.getLocationInWindow(location);
Rect r = new Rect();
view.getGlobalVisibleRect(r);
int height = r.bottom - r.top;
int newTop = r.bottom - view.getHeight() / 2 - this.mKeyboardView.getHeight() / 2;
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) this.mKeyboardView.getLayoutParams();
params.setMargins(0, newTop, 0, 0);
this.mKeyboardView.setLayoutParams(params);
this.mKeyboardView.invalidate();
this.mKeyboardView.post(new Runnable() {
#Override
public void run() {
int[] location = new int[2];
Rect r2 = new Rect();
mKeyboardView.getLocalVisibleRect(r2);
double abc = r2.bottom;
}
});
}
The way I would do this is, is by calculating it with the following info:
the location of the view on screen (getLocationOnScreen(int[]))
the width/height of the view (getMeasuredHeight() and getMeasuredWidth())
the width/height of the screen
If you have this information, it isn't that difficult anymore to calculate everything you need. Just make sure that you are using the same units (pixels, dpis etc) for every value.
its kind of a late answer but for future reference I created a library for this purpose.If your view is inside a scrollview you can use my library
It adds an onScrollChangedListener from ViewTreeObserver and every time scroll changes recalculates the visible percentage of the view and calls a custom listener.
You can find it here : PercentVisibleLayout
I have 3 VerticalViewPagers next to each other. Each view pager contains only images. Here's example:
when user clicks on the image, I need to make an EditText. The EditText has to be on an exact spot for each image. So I need to get the position of the image, add some constant and make there a EditText. How to do this?
Note: I tried getLocationOnScreen, for the leftmost image, i got [0,50] back and when I set margin top = 50 and left = 0 for the EditText, it was above the image.
Inflating the items:
public Object instantiateItem(ViewGroup collection, final int position) {
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View rootView = layoutInflater.inflate(R.layout.item_layout, null);
final ImageView imageView = (ImageView) rootView.findViewById(R.id.item);
final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
collection.addView(rootView, 0);
rootView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int[] pos = new int[2];
imageView.getLocationOnScreen(pos);
params.leftMargin = coordinates.get(0).first;
params.topMargin = coordinates.get(0).second;
EditText editText = new EditText(context);
editText.setLayoutParams(params);
((RelativeLayout) rootView).addView(editText);
}
}
});
return rootView;
item_layout.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/item_relative_layout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/item"
android:contentDescription="#string/imageContent" />
</RelativeLayout>
You must also take taskbar height into calculation, since the getLocationOnScreen is the location when the layout is below the taskbar. When positioning an object on a screen, the top left corner of the applicationĀ“s layout is [0,0], but it is not the [0,0] point of the whole screen, because the application layout starts below the taskbar. The point [0,0] in the getLocationOnScreen lays in the top left corner of the whole screen so you will get the coordinates slightly moved by the taskbar height.
So when positioning your EditText, just add the taskbar height to the y-coordinate and you should be good.
I am very new to Android and I am having problems figuring out how to layout views within a RelativeLayout programmatically. What I want to do is create 4 circles (child views) with a certain radius (say 50px) in the center of the RelativeLayout container, so it would look like I have an imaginary square in the center of the RelativeLayout and each vertex is the center for one of the circles.
I am able to draw the circle in the view; that is simple enough :)
class CircleView extends View {
...
protected void onDraw(Canvas canvas) {
// draw circle on canvas
}
}
What I cannot figure out is how to layout the views. It seems to draw them on top of each other, even though I am setting LayoutParams and an Id for each of the child views.
class Circles extends RelativeLayout {
public Circles(Context c) {
super(c);
addChildViews();
}
...
private void addChildViews() {
final Context c = getContext();
final CircleView v0 = new CircleView(c);
v0.setId(0);
final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.LEFT_OF, 1);
params.addRule(RelativeLayout.ABOVE, 2);
v0.setLayoutParams(params);
addView(v0);
....
// and so on, with relative layout params for other 3 views
}
}
Can somebody put me on the right track please? I also don't know if I am not calling addChildViews at the right time in the drawing cycle, and if this is what is leading to them being drawn on top of each other. Many thanks for any help.
Two things
1)The default action of a View is to fill its parent, so by applying (LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT) as your LayoutParams, you're creating four views with heights and widths the size of your parent layout (presumably the screen), so you'd only see one as the others would be positioned offscreen.
To fix this, either set the size you want the circles to be as your LayoutParms,
float dpi = getResources().getDisplayMetrics().density;
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams((int)(50.0f * dpi), (int)(50.0f * dpi));
or you could override the onMeasure(int x, int y) method in your Circle View like so
#Override
public void onMeasure(int x, int y) {
float dpi = getResources().getDisplayMetrics().density;
setMeasuredDimension((int)(50.0f * dpi), (int)(50.0f * dpi));
}
2) Don't set your View id to 0...I can't remember if it's system reserved or what, but it doesn't play nice.
Additionally, if you want all the circles centered in your Circles, you'll want to set its gravity to center like so.
public class Circles extends RelativeLayout {
public Circles (Context ctx) {
super(ctx);
this.setGravity(Gravity.CENTER);
addViewChildren();
}
This will center all of the Circles children, giving you the desired result.
I want to add a view inside a FrameLayout programmatically and to place it in a specific point within the layout with a specific width and height. Does FrameLayout support this? If not, should I use an intermediate ViewGroup to achieve this?
int x; // Can be negative?
int y; // Can be negative?
int width;
int height;
View v = new View(context);
// v.setLayoutParams(?); // What do I put here?
frameLayout.addView(v);
My initial idea was to add an AbsoluteLayout to the FrameLayout and place the view inside the AbsoluteLayout. Unfortunately I just found out that AbsoluteLayout is deprecated.
Any pointers will be much appreciated. Thanks.
The following example (working code) shows how to place a view (EditText) inside of a FrameLayout. Also it shows how to set the position of the EditText using the setPadding setter of the FrameLayout (everytime the user clicks on the FrameLayout, the position of the EditText is set to the position of the click):
public class TextToolTestActivity extends Activity{
FrameLayout frmLayout;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
frmLayout = (FrameLayout)findViewById(R.id.frameLayout1);
frmLayout.setFocusable(true);
EditText et = new EditText(this);
frmLayout.addView(et,100,100);
frmLayout.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("TESTING","touch x,y == " + event.getX() + "," + event.getY() );
frmLayout.setPadding(Math.round(event.getX()),Math.round(event.getY()) , 0, 0);
return true;
}
});
}
}
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="fill_parent"
android:layout_height="fill_parent">
<FrameLayout
android:id="#+id/frameLayout1"
android:layout_height="fill_parent" android:layout_width="fill_parent">
</FrameLayout>
</LinearLayout>
You can also add a margin around the newly added view to position it inside the FrameLayout.
FrameLayout frameLayout = (FrameLayout) findViewById(R.id.main); // or some other R.id.xxx
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.setMargins(0, metrics.heightPixels - 20, 0, 0);
View v = new View(context);
v.setLayoutParams(params);
frameLayout.addView(v);
This will position the FrameLayout 20 pixels from the bottom of the screen.
Edit: completed the example so it stands by itself. And oh, yes it does work.
It's true that with FrameLayout all children are pegged to the top left of the screen, but you still have some control with setting their padding. If you set different padding values to different children, they will show up at different places in the FrameLayout.
From the link Quinn1000 provided:
You can add multiple children to a FrameLayout, but all children are pegged to the top left of the screen.
This means you can't put your View at a specific point inside the FrameLayout (except you want it to be at the top left corner :-)).
If you need the absolute positioning of the View, try the AbsoluteLayout:
A layout that lets you specify exact locations (x/y coordinates) of its children. Absolute layouts are less flexible and harder to maintain than other types of layouts without absolute positioning.
As for setting the width and height of the View, also like Quinn1000 said, you supply the v.setLayoutParams() method a LayoutParams object, depending on the container you chose (AbsoluteLayout, LinearLayout, etc.)
The thread here on stackOverflow at
How do you setLayoutParams() for an ImageView?
covers it somewhat.
For instance:
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(30, 30);
yourImageView.setLayoutParams(layoutParams);
implies that you need to be defining a LinearLayout.LayoutParams (or in your case a FrameLayout.layoutParams) object to pass to the setLayoutParams method of your v object.
At
http://developer.android.com/reference/android/widget/FrameLayout.html
it almost makes it looks like you could ask your v to:
generateDefaultLayoutParams () via this method if you have not defined the parameters specifically.
But it's late, and those links are making my eyes bleed a little. Let me know if they nhelp any :-)