I am trying to make a Custom ChedckBox and having a trouble centring the button part of it. Here is the code :
<FrameLayout
android:layout_width="#dimen/checkbox_height"
android:layout_height="#dimen/checkbox_height"
android:background="#drawable/checkbox_background_info"
android:padding="5dp" >
<CheckBox
android:id="#+id/classification_uk_selected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="#drawable/checkbox_star_info">
</CheckBox>
</FrameLayout>
The Drawbale just has a yellow star with no background for enabled and grey one for disabled. It stays to the left handside and I cannot get it centered
Thanks for help
If you change FrameLayout to RelativeLayout you can just set android:center_in_parent to true;
in your frame layout set gravity as center.
android:gravity="center"
I dont believe this is possible (atleast not in API version 8)
Here is the code from CompoundButton.onDraw, which seems to indicate the CompoundButton draws buttonDrawable (which represents your checkbox image) within a bounding rect which has an offset of 0 in the parent view.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final Drawable buttonDrawable = mButtonDrawable;
if (buttonDrawable != null) {
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
final int height = buttonDrawable.getIntrinsicHeight();
int y = 0;
switch (verticalGravity) {
case Gravity.BOTTOM:
y = getHeight() - height;
break;
case Gravity.CENTER_VERTICAL:
y = (getHeight() - height) / 2;
break;
}
buttonDrawable.setBounds(0, y, buttonDrawable.getIntrinsicWidth(), y + height);
buttonDrawable.draw(canvas);
}
}
Instead, try setting the width of the CheckBox to be slightly greater (in dp) than the size of the image you're using. This squeezes the button drawable and it doesn't render with all the white space on the right.
Related
I'm using a TouchImageView in my app in which I have an image which is larger than the screensize. When I start the activity that contains my TouchImageView it currently automatically shows the center of my image in the middle of the screen. I have to manually (using a drag gesture) make the top left-corner visibe. However, I would like to have the top-left corner of the image visible in the top left corner of my screen by default.
I tried imgView.setScrollPosition(0,0), but without any result.
I also tried setting the scaletype to "matrix", but this zooms out on the image, while I want the image to be shown in it's original size. Scaletypes fitStart and fitEnd are not supported by TouchImageView.
How can I scroll to the top left corner of my TouchImageView?
Here's my 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">
<com.frankd.wttv.TouchImageView
android:id="#+id/imageView"
android:layout_width = "wrap_content"
android:layout_height ="wrap_content"
android:scaleType="matrix"/>
</LinearLayout>
And here is how I open the layout and set the image.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.myLayout);
//set timetable image
TouchImageView imgView = (TouchImageView)findViewById(R.id.imageView);
imgView.setImageResource(R.drawable.myImage);
//TODO: scroll to top left corner of image
}
The cause of the problem is that scrollToPosition(x,y) in TouchImageView doens't use the x and y pixels as input, but instead a number between 0 and 1 that reflects a proportion of the image size.
Also the scrollToPosition(x,y) sets a point of the image in the center of the TouchImageView. So if you call scrollToPosition(0.5,0.5) on the TouchImageView, the center of the image is being displayed at the center of the TouchImageView. We need to calculate which point of the image needs to be placed in the center of the TouchImageView to get it aligned nicely.
I created the function scrollToTopLeft() in TouchImageView.java, which only works if you call it at the end of onMeasure() from within the TouchImageView.java file. If you call it earlier the getWidth() and getHeight() will return 0 as the view hasn't been sized yet.
public void scrollToTopLeft() {
try {
float x, y, viewWidth, viewHeight, viewCenterX, viewCenterY, imageWidth, imageHeight;
//these calls will only work if called after (or at the end of) onMeasure()
viewWidth = this.getWidth();
viewHeight = this.getHeight();
// get center of view
viewCenterX = viewWidth / 2;
viewCenterY = viewHeight / 2;
// get image height and width
imageWidth = getImageWidth();
imageHeight = getImageHeight();
//calculate the x and y pixels that need to be displayed in at the center of the view
x = viewWidth / imageWidth * viewCenterX;
y = viewHeight / imageHeight * viewCenterY;
//calculate the value of the x and y pixels relative to the image
x = x / imageWidth;
y = y / imageHeight;
setScrollPosition(x, y);
} catch (Exception E) {
Log.v(TAG, E.toString());
}
}
Given a simple RelativeLayout like this:
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#0fffff">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="#drawable/img001" />
</RelativeLayout>
the left/top spacing between the layout border and the image border depends on the W/H ratio of the image being load in the imageView.
How can I know (programmatically) the real margin (width and height of the cyan area) after an image is shown in this layout?
This method will calculate the new rectangle which bounds the object after FIT_CENTER and all other related values.
It should work on all cases of object and container.
public static Rect calculateFitCenterObjectRect(float containerWidth, float containerHeight, float objectWidth, float objectHeight) {
// scale value to make fit center
double scale = Math.min( (double)containerWidth / (double)objectWidth, (double)containerHeight / (double)objectHeight);
int h = (int) (scale * objectHeight); // new height of the object
int w = (int) (scale * objectWidth); // new width of the object
int x = (int) ((containerWidth - w) * 0.5f); // new x location of the object relative to the container
int y = (int) ((containerHeight - h) * 0.5f); // new y location of the object relative to the container
return new Rect(x, y, x + w, y + h);
}
You can use FrameLayout to position the view wherever you want after using the previous method with the new x, y, width, height of the scaled object.
If you know the width of the ImageView, like this
int ivWidth = iv.getMeasuredWidth();
and the total width of the layout (your RelativeLayout), like this
int layoutWidth = yourLayout.getWidth();
then, you can easily get the horizontal margin, like this
int horizontalMargin = (layoutWidth - ivWidth)/2;
And the same goes for height.
You should call functions like getWidth and getHeight after the dimensions of your layout have been calculated, as described by Veer's and Khan's answer on How to get the width and height of an Image View in android?.
Calling getWidth or getHeight in onCreate will return 0.
I'm trying to figure out how to draw a Square within my onDraw method in Android.
The square must be positioned in the exact center of the canvas
(Not the screen)
The padding/spacing on the left and right hand side of the square should be
equal
The padding/spacing on the top and bottom of the square should be equal
The size of the square should be relatively large, about 90% of the
canvas's width
Here's what I have so far.
//this.rect is an instance of Rect() which later gets called in the canvas.drawRect() method
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = this.getMeasuredWidth();
int height = this.getMeasuredHeight();
int padding = (width / 10);
this.size = width - padding;
this.rect.set(padding,padding,size,size);
}
The code above draws the square but I'm not sure how to get it to center in the canvas. I am also open to using another technique that does not involve using a Rect.
What properties do I need to set to this Rect() in order for the canvas.drawRect(rect,paint) to draw the rectangle directly in the center of the canvas?
Edit:
Terribly drawn example of what I want to achieve
Assuming width is the width of the canvas, I guess you're missing substracting the padding twice.-
this.size = width - padding * 2;
EDIT
Since we're talking about a rectangle here, you'll need to do some more changes to your code, and calculate different top and left padding .-
int width = this.getMeasuredWidth();
int height = this.getMeasuredHeight();
int paddingLeft = (width / 10);
size = width - paddingLeft * 2;
int paddingTop = (height - size) / 2;
this.rect.set(paddingLeft,paddingTop,size,size);
EDIT 2
Maybe a clearer approach would start calculating the size of your square.-
size = width * 0.9f;
int paddingLeft = (width - size) / 2;
int paddingTop = (height - size) / 2;
this.rect.set(paddingLeft,paddingTop,size,size);
This question already has answers here:
Handling click events on a drawable within an EditText
(41 answers)
Closed 8 years ago.
In my app I have a EditText with a search Icon on the right side. I used the code given below.
<EditText
android:id="#+id/search"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="4dip"
android:layout_weight="1"
android:background="#drawable/textfield_search1"
android:drawableLeft="#drawable/logo"
android:drawableRight="#drawable/search_icon"
android:hint="Search Anything..."
android:padding="4dip"
android:singleLine="true" />
I want to set the onClickListener for the search icon image assigned to the right drawable
of EditText. How is it possible?
public class CustomEditText extends androidx.appcompat.widget.AppCompatEditText {
private Drawable drawableRight;
private Drawable drawableLeft;
private Drawable drawableTop;
private Drawable drawableBottom;
int actionX, actionY;
private DrawableClickListener clickListener;
public CustomEditText (Context context, AttributeSet attrs) {
super(context, attrs);
// this Contructure required when you are using this view in xml
}
public CustomEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
public void setCompoundDrawables(Drawable left, Drawable top,
Drawable right, Drawable bottom) {
if (left != null) {
drawableLeft = left;
}
if (right != null) {
drawableRight = right;
}
if (top != null) {
drawableTop = top;
}
if (bottom != null) {
drawableBottom = bottom;
}
super.setCompoundDrawables(left, top, right, bottom);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
Rect bounds;
if (event.getAction() == MotionEvent.ACTION_DOWN) {
actionX = (int) event.getX();
actionY = (int) event.getY();
if (drawableBottom != null
&& drawableBottom.getBounds().contains(actionX, actionY)) {
clickListener.onClick(DrawablePosition.BOTTOM);
return super.onTouchEvent(event);
}
if (drawableTop != null
&& drawableTop.getBounds().contains(actionX, actionY)) {
clickListener.onClick(DrawablePosition.TOP);
return super.onTouchEvent(event);
}
// this works for left since container shares 0,0 origin with bounds
if (drawableLeft != null) {
bounds = null;
bounds = drawableLeft.getBounds();
int x, y;
int extraTapArea = (int) (13 * getResources().getDisplayMetrics().density + 0.5);
x = actionX;
y = actionY;
if (!bounds.contains(actionX, actionY)) {
/** Gives the +20 area for tapping. */
x = (int) (actionX - extraTapArea);
y = (int) (actionY - extraTapArea);
if (x <= 0)
x = actionX;
if (y <= 0)
y = actionY;
/** Creates square from the smallest value */
if (x < y) {
y = x;
}
}
if (bounds.contains(x, y) && clickListener != null) {
clickListener
.onClick(DrawableClickListener.DrawablePosition.LEFT);
event.setAction(MotionEvent.ACTION_CANCEL);
return false;
}
}
if (drawableRight != null) {
bounds = null;
bounds = drawableRight.getBounds();
int x, y;
int extraTapArea = 13;
/**
* IF USER CLICKS JUST OUT SIDE THE RECTANGLE OF THE DRAWABLE
* THAN ADD X AND SUBTRACT THE Y WITH SOME VALUE SO THAT AFTER
* CALCULATING X AND Y CO-ORDINATE LIES INTO THE DRAWBABLE
* BOUND. - this process help to increase the tappable area of
* the rectangle.
*/
x = (int) (actionX + extraTapArea);
y = (int) (actionY - extraTapArea);
/**Since this is right drawable subtract the value of x from the width
* of view. so that width - tappedarea will result in x co-ordinate in drawable bound.
*/
x = getWidth() - x;
/*x can be negative if user taps at x co-ordinate just near the width.
* e.g views width = 300 and user taps 290. Then as per previous calculation
* 290 + 13 = 303. So subtract X from getWidth() will result in negative value.
* So to avoid this add the value previous added when x goes negative.
*/
if(x <= 0){
x += extraTapArea;
}
/* If result after calculating for extra tappable area is negative.
* assign the original value so that after subtracting
* extratapping area value doesn't go into negative value.
*/
if (y <= 0)
y = actionY;
/**If drawble bounds contains the x and y points then move ahead.*/
if (bounds.contains(x, y) && clickListener != null) {
clickListener
.onClick(DrawableClickListener.DrawablePosition.RIGHT);
event.setAction(MotionEvent.ACTION_CANCEL);
return false;
}
return super.onTouchEvent(event);
}
}
return super.onTouchEvent(event);
}
#Override
protected void finalize() throws Throwable {
drawableRight = null;
drawableBottom = null;
drawableLeft = null;
drawableTop = null;
super.finalize();
}
public void setDrawableClickListener(DrawableClickListener listener) {
this.clickListener = listener;
}
}
Also Create an Interface with
public interface DrawableClickListener {
public static enum DrawablePosition { TOP, BOTTOM, LEFT, RIGHT };
public void onClick(DrawablePosition target);
}
Still if u need any help, comment
Also set the drawableClickListener on the view in activity file.
editText.setDrawableClickListener(new DrawableClickListener() {
public void onClick(DrawablePosition target) {
switch (target) {
case LEFT:
//Do something here
break;
default:
break;
}
}
});
This has been already answered but I tried a different way to make it simpler.
The idea is using putting an ImageButton on the right of EditText and having negative margin to it so that the EditText flows into the ImageButton making it look like the Button is in the EditText.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="#+id/editText"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="Enter Pin"
android:singleLine="true"
android:textSize="25sp"
android:paddingRight="60dp"
/>
<ImageButton
android:id="#+id/pastePin"
android:layout_marginLeft="-60dp"
style="?android:buttonBarButtonStyle"
android:paddingBottom="5dp"
android:src="#drawable/ic_action_paste"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Also, as shown above, you can use a paddingRight of similar width in the EditText if you don't want the text in it to be flown over the ImageButton.
I guessed margin size with the help of android-studio's layout designer and it looks similar across all screen sizes. Or else you can calculate the width of the ImageButton and set the margin programatically.
You don't have access to the right image as far my knowledge, unless you override the onTouch event. 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>
I know this is quite old, but I recently had to do something very similar, and came up with a much simpler solution.
It boils down to the following steps:
Create an XML layout that contains the EditText and Image
Subclass FrameLayout and inflate the XML layout
Add code for the click listener and any other behavior you want... without having to worry about positions of the click or any other messy code.
See this post for the full example:
Handling click events on a drawable within an EditText
Please use below trick:
Create an image button with your icon and set its background color to be transparent.
Put the image button on the EditText
Implement the 'onclic'k listener of the button to execute your function
I need to develop an app in which buttons are hexagons and all of them are placed next to each other creating a grid. Given my little experience in Android, I wonder if GridView is the best approach for this. If that is the case, how could I place the hexagons next to each other?
I have this by now
Using this layout in main.xml:
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="0dp"
android:verticalSpacing="0dp"
android:horizontalSpacing="0dp"
android:numColumns="4"
android:columnWidth="0dp"
android:stretchMode="columnWidth"
android:gravity="top"
/>
And this is what I am trying to get:
I would need some help to place hexagons tied to each other in a fixed structure. I've been playing around with the layout values with no sucess. Would TableView be a better approach?
Thanks a lot
Here is some code I used in an app (it's called 'Connect3, if you'd like to play it :) ). It is a custom layout class that draws hexagonal images in a grid. The grid can be triangular or a tilted rectangle.
The code calculates the bounds (in pixels relative to the origin of the hexgrid) of each imageview and then calls imageView.layout(left,top,right,bottom) to set the calculated bounds. The calculations aren't that hard. The main parameter is the radius of the hexagon. From that, the total hight, total width, effective hight and effective width (the height/width of the imageview respectively the distance between the top/left bounds of two consecutive views). Then it comes down to some simple for loops to draw them.
To make the views clickable, just set an onClickListener when you create them. (I made it a class member, because it made things easier).
The onMeasure functions just calculates the total width and height of the view and calls setMeasuredDimension with those values.
The images used for all this are just the single hexagons as you see them right below the actionbar. Note that the images are squares.
#Override
protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) {
Log.d(TAG, "board.onlayout called with size "+mSize+" l: "+l+" r: "+r+" t: "+t+" b: "+b);
//If the dimensions of the board haven't changed, a redraw isn't necessary. Just update the images of the views instead by calling invalidate().
if (!changed && !mSizeInvalidated) {
invalidate();
return;
}
int childCount = getChildCount();
//Calculate some useful parameters.
float radius = getResources().getDimension(R.dimen.radius);
float verticalMargin = -radius / 4;
float horizontalMargin = ((float) Math.sqrt(3) / 2 - 1) * radius;
float height = 2 * radius;
float width = height;
float effectiveHeight = height + 2 * verticalMargin;
float effectiveWidth = width + 2 * horizontalMargin;
float totalHeight=(radius * (3 * mSize + 1)) / 2;
float totalWidth;
switch (mGameType) {
case Connect3Turn.GAME_TYPE_HEX:
totalWidth = (((float) mSize * 3 - 1)/ 2) * ((float) Math.sqrt(3)) * radius;
break;
case Connect3Turn.GAME_TYPE_Y:
default:
totalWidth = mSize * ((float) Math.sqrt(3)) * radius;
}
LayoutParams layoutParams = new LayoutParams((int) width, (int) height);
//Code to calculate the offsets for horizontal and vertical centering (this is an option in the .xml file)
//The GAME_TYPE_HEX creates a tilted rectangular board and GAME_TYPE_Y creates a triangular board.
float x_offset_row;
switch (mGameType) {
case Connect3Turn.GAME_TYPE_Y:
x_offset_row=(mSize - 1) * effectiveWidth / 2 + horizontalMargin;
break;
case Connect3Turn.GAME_TYPE_HEX:
default:
x_offset_row=0;
}
switch (mCenterHorizontal) {
//the left side of the grid should be at non-negative coordinates.
case 1: {
x_offset_row += Math.max(0,(r-l-totalWidth)/2);
break;
}
case 2: {x_offset_row += Math.max(0,(r-l-totalWidth));
break;
}
case 0:
default: {
break;
}
}
//calculate the y_offset for vertical centering.
float y_offset = 0;
switch (mCenterVertical) {
case 1: {
y_offset = Math.max(0, (b - t - totalHeight) / 2);
break;
}
case 2: {
y_offset = Math.max(0, (b - t -totalHeight));
break;
}
}
int cell = 0;
for (int row = 0; row < mSize; ++row) {
float x_offset = x_offset_row;
int rowLength;
//The row length depends on the board-type we want to draw.
switch (mGameType){
case Connect3Turn.GAME_TYPE_HEX:
rowLength=mSize;
break;
case Connect3Turn.GAME_TYPE_Y:
default:
rowLength=row+1;
}
Log.d(TAG, "Drawing row "+row+" with "+rowLength+" cells.");
for (int col = 0; col < rowLength; ++col) {
ImageView v;
if (cell < childCount) {
v = (ImageView) getChildAt(cell);
} else {
v = new ImageView(super.getContext());
v.setLayoutParams(layoutParams);
v.setOnClickListener(onClickListener);
addViewInLayout(v, cell, v.getLayoutParams(), true);
}
//Set the image (color) of the cell and put its index in a tag, so we can retrieve the number of the clicked cell in the onClickListener.
v.setImageResource(mImageIds[mImages[cell]]);
v.setTag(cell);
//Set the bounds of the image, which will automatically be cropped in the available space.
v.layout((int) x_offset, (int) y_offset, (int) (x_offset + width), (int) (y_offset + height));
x_offset += effectiveWidth;
++cell;
}
y_offset += effectiveHeight;
//The offset of the next row, relative to this one, again depends on the game type.
switch(mGameType){
case Connect3Turn.GAME_TYPE_Y:
x_offset_row -= effectiveWidth / 2;
break;
case Connect3Turn.GAME_TYPE_HEX:
x_offset_row += effectiveWidth / 2;
}
}
//We updated all views, so it is not invalidated anymore.
mSizeInvalidated=false;
}
You can always work with it like if it was a normal grid. But instead of drawing a square, you draw an hexagon.
http://img811.imageshack.us/img811/9229/uyje.png
But then, you move the odd lines half the width of the hexagon in a way that they will fit with the pair lines.
http://img822.imageshack.us/img822/2298/e5cq.png