Android Circle button - android

How I can to make custom circle button? (only make clicks on circle )
Is any way to make it with circle png file?
I tried with imageView override onTouch method but it works very badly because view.getWidth(), view.getHeight() and view.getTop... methods works very bad
public boolean inCircle(MotionEvent e, int radius, int x, int y) {
int dx = (int) (e.getX() - x);
int dy = (int) (e.getY() - y);
double d = Math.sqrt((dx * dx) + (dy * dy));
if (d < radius)
return true;
return false;
}
Thanks.

Its very simple. Create a custom shape drawable and set that as the background of your view. Example:
round_button_drawable.xml in drawable/
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="#android:color/holo_orange_dark"/>
</shape>
set this drawable as the background of any view.
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/round_button_drawable"
android:text="btn"
/>

Another way would be to extend Button and override its onDraw method
You can then draw a circle on the canvas using canvas.drawCircle method.
You can also draw the circle.png file on the canvas using Drawable.draw method

Dont go for complex logic just select any rounded image and set that image as a background of your simple button it will look like simple round button and it will accept click only on that round shape.

there is ImageButton class which can serve ur purpose..

Related

Custom progress bar with images or Image view with clipdrawable

I have been looking for tutorials on custom progress bars and 95% of what I found was how to customize using colors and gradients NOT with images (basically an image of empty bar with image or full bar on top). When I try to use images for progress bar, the dimensions are wrong ( wrap content does not work properly and it is half truncated).
I was able to achieve a successful bar with images using image with clipdrawble and level setting.
SOOO, is ProgressBar with images used for its background/progress frowned upon and I should use imageview instead?
The key is to make sure ProgressBar accounts for your custom drawable's dimensions. One way to do it is to override the onMeasure. Here is a rough sketch of your custom class's onMeasure implementation (compare this against ProgressBar's implementation - you will notice the subtle changes) :
#Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
// the super's onMeasure method ignores the dimensions of the custom progress drawable
// if they are greater than a specified height & width (mMaxHeight & mMaxWidth). It simply uses those
// default dimensions for the drawable, consequently resizing them; which is not suitable for larger drawables.
// So, it is necessary to override this method to allow the ProgressBar to account for the drawable's original
// dimensions and draw the image/drawable accordingly.
Drawable d = getProgressDrawable();
int dw = 0;
int dh = 0;
if (d != null) {
dw = d.getIntrinsicWidth();
dh = d.getIntrinsicHeight();
}
int[] state = getDrawableState();
if(mProgressDrawable != null && mProgressDrawable.isStateful())
mProgressDrawable.setState(state);
dw += getPaddingLeft() + getPaddingRight();
dh += getPaddingTop() + getPaddingBottom();
setMeasuredDimension(resolveSize(dw, widthMeasureSpec), resolveSize(dh, heightMeasureSpec));
}
You can then set your empty bar as the background for the custom ProgressBar like you would usually do for a view - android:background="#drawable/empty_bar"
The next part is to set the progressDrawable, for which you will have to use a <layer-list>, as we want to closely match the progress bar's drawable structure (default drawable). Here is a sample:
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#android:id/background">
<shape>
<solid android:color="#00000000"/>
</shape>
</item>
<item android:id="#android:id/progress">
<clip
android:clipOrientation="vertical"
android:gravity="bottom"
android:drawable="#drawable/full_bar">
</clip>
</item>
</layer-list>
And finally to animate the progressbar you could use an ObjectAnimator:
final ObjectAnimator animator = ObjectAnimator
.ofInt(progressBar, "progress", 0, 100)
.setDuration(2000);
animator.start();

Android - Multiple colors & size in drawable shape style

I'm trying to have a circle background for my TextView, so I created a shape style as below.
But I need to have multiple colors with multiple sizes (while the textSize stays constant), so I need to set the width/height in the style.
From my understanding..Layer List puts all the shapes on top of one another? Because I need to call it 12 times at different places, so it seems quite cumbersome to have 12 shape style xmls.
Is there a better way to have all the different shape/size combinations inside one XML?
Shape Style:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<corners android:radius="10dp"/>
<solid android:color="#color/girl_orange"/>
<size
android:width="84dp"
android:height="84dp" />
</shape>
Called in layout xml by:
android:background="#drawable/skills_circle"
Thanks in advance!!
create a custom Drawable, this way you can have milions combinations of size/color:
class CircleDrawable extends Drawable {
...
}
So I followed the advice from pskink and created a CircleDrawable class.
It works quite nicely for my application (although I don't know if it's the right way...), so I thought I'd share it.
public CircleDrawable(Bitmap bitmap, Context context) {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
CircleDrawable.context = context;
drawable = new ShapeDrawable(new OvalShape());
setColor(); // supports multiple color
setSize(); //supports multiple size
}
private void setColor() {
// some algorithm to pick the right color...
if (...)
int color = context.getResources().getColor(R.color.pale_blue);
paint.setColor(color);
}
/*
* algorithm to set size here...
*/
#Override
public void draw(Canvas canvas) {
//draw circle in the middle of the TextView
canvas.drawCircle(textViewSize, textViewSize, circleSize, paint);
}
And in the main code where I need to dynamically draw the circles:
final float scale = getApplicationContext().getResources().getDisplayMetrics().density;
int pixels = (int) (107.0f * scale + 0.5f);
skills.setWidth(pixels);
skills.setHeight(pixels);
skills.setBackground(new CircleDrawable(null, getApplicationContext()));
And I ended up with a bunch of circles with different shapes and colors.

How I can set partly the background color

I have a class that implement a view
**DrawView.class**
public class DrawView extends View {
Paint paint = new Paint();
public DrawView(Context context, AttributeSet attrs){
super(context, attrs);
}
and my file.xml
<com.example.sliding.DrawView
android:id="#+id/tv_listRow_item1"
android:tag="tv_listRow_item1_1"
android:layout_height="0dip"
android:layout_width="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:width="100dip"
android:height="30dip"
android:background="#drawable/textview_listrow_border"/>
This view have 30 dip of height. How can i color only 30% of this 30 dip?
Anyone can give me an example?
Thanks for your time and help.
I'm not entirely sure this will work, but you could make a 9 patch that is 30% color and 70% transparent, then define two stretchable areas (one for each) in the appropriate percentages. When 9 patches are stretched, they're supposed to respect the ratios of multiple stretch zones, so I think it would work.
http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch
One way is by using a LayerDrawable
But this would only work when the heigt of the view is fixed at 80dp.
Create an xml file in your drawable folder.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="#FFFFFFFF" />
</shape>
</item>
<item android:top="10dp">
<shape >
<solid android:color="#FF000000"/>
</shape>
</item>
<item android:top="60dp">
<shape>
<solid android:color="#FFFFFFFF"/>
</shape>
</item>
</layer-list>
And set this as the background to the view.
I NEED A FUNCTION THAT HAVE 2 PARAMETERS. This FIRST INDICATE THE BEGIN OF COLOR. THE SECOND INDICATE THE END. hEIGHT=80dp. THE FIRST PARAMETER FOR EXAMPLE IS 20 THE SECOND IS 30 FOR EXAMPLE. The pixels inside this interval have a color…..
I guess that the easiest way to do it is to override the onDraw(Canvas canvas) function and draw a rectangle like this.
double mStart = -1;
double mEnd = -1;
public void addRectangle( double startInPercent, double endInPercent ) {
if( startInPercent < 0 || endInPercent > 1 || endInPercent > startInPercent )
return;
mStart = startInPercent;
mEnd = endInPercent;
//this will make the view to refresh the UI
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if( mStart >= 0 && mEnd >= 0)
canvas.drawRect(0, getHeight() * mStart, getWidth(), getHeight() * mEnd, mPaint);
}
this code will draw a rectangle as specified in the addRectangle() method. In my implementation I intend the parameters of that function to per % of the Height of the view.
here is the documentation of that drawRect( ... ) call. Changing the parameters you can draw at the top, bottom left and right as you prefer.
In order to get the color you want you have to init mPaint in the view constructor like this:
Paint mPaint = new Paint();
mPaint.setColor( Color.RED );
of course this is the dumbest code possible, you can play around this 2 concept to basically get what you want.
the main class to do this ( and almost everything in the Andorid UI ) are:
Canvas
View
Paint

Android - How to detect transparency of the clicked area of custom shaped buttons

I have some irregular shaped buttons, created as ImageButtons. The "android:src" attribute of the ImageButtons are .PNG files with transparent backgrounds. And the parent layout of these ImageButtons, has a custom background image, which is defined with "android:background" attribute. So the background of the activity is not transparent or just black.
My question is; how can I detect if a click on a button is on the transparent area of the source image, or on the visible part of the source image?
I tried using onTouchListener to get the coordinates of the event and make a decision according to the color of the pixel; but since the background is colorful, I couldn't get to a point.
Any help is very much appreciated. Thanks in advance!
Hi bro i think this link may help you.
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/1.5_r4/android/view/View.java#View.dispatchTouchEvent%28android.view.MotionEvent%29
You need to override this method in your custom button to return false if point is not in the desired area. I suggest you go about it like this:
public static class MyButton extends ImageButton {
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
int iX = (int) event.getX();
int iY = (int) event.getY();
// TODO Or use a more sophisticated, pixel value-based condition
if (!(iX >= 0 & iY >= 0 & iX < TheBitmap.getWidth() & iY < TheBitmap.getHeight())) {
return false;
}
return super.dispatchTouchEvent(event)
}
}

Can I increase a buttons onclick-area programmatically?

Sometimes I have a button in my UI that it is so small that it is difficult to click. My solution so far has been to add a transparent border around the button in photoshop. Just increasing the padding on the button does not work, since this will also stretch the image. Since it is kind of a fuss to open photoshop each time I want to change the clickable surface, is there any way to do this programmatically? I have tried placing a framelayout behind the button and make it clickable, but then the button wont change appearance on touch as it should. Ofcourse I could also add a ontouchlistener on the framelayout which changes the buttons appearance, but then it quite some code if I have several of those buttons.
Cheers,
Me personally, I'd use a TouchDelegate. This lets you deal with the touch target, and the visual view bounds as two different things. Very handy...
http://developer.android.com/reference/android/view/TouchDelegate.html
I have just found a neat way to solve this problem.
Surround the button with a say a LinearLayout that has the padding round the button.
Add the same onclick to the LinearLayout as the Button.
In the Button set the duplicateParentState to true which make the button highlight when you click outside the button but inside the LinearLayout.
<LinearLayout
android:layout_height="fill_parent"
android:onClick="searchButtonClicked"
android:layout_centerVertical="true"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:paddingRight="10dp"
android:paddingLeft="30dp">
<Button
android:id="#+id/search_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/toggle_button_selector"
android:textColor="#fff"
android:text="Search"
android:focusable="true"
android:textStyle="bold"
android:onClick="searchButtonClicked"
android:layout_gravity="center_vertical"
android:duplicateParentState="true"/>
</LinearLayout>
This is a very late "me too," but after coming to this and other questions looking for a solution, I found a simple, elegant solution of my own.
Another question complained that the transparent background of their image was not clickable. If that is an issue, this seems to get around that as well.
Here's the button:
<ImageButton
android:id="#+id/arrowUp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/arrow_up"
android:background="#drawable/clear_button_background" />
The relevant lines are the last two. "#drawable/arrow_up" is a few button states in *.png files defined in a drawable *.xml file like this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true"
android:drawable="#drawable/tri_up_blue" /> <!-- pressed -->
<item android:state_selected="true"
android:drawable="#drawable/tri_up_blue" /> <!-- selected -->
<item android:state_focused="true"
android:drawable="#drawable/tri_up_blue" /> <!-- focused -->
<item android:drawable="#drawable/tri_up_green" /> <!-- default -->
</selector>
Just your basic button. Nothing special. And "#drawable/clear_button_background" is just this:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#android:color/transparent"/>
<size android:width="20dp" android:height="30dp" />
</shape>
The height and width here are the clickable area, resize as needed. You can reuse this for as many buttons as you need in a single view, unlike the absurdly detailed TouchDelegate. No additional listeners. It doesn't add any views or groups to your hierarchy and you won't be messing around with padding and margins all day.
Simple. Elegant.
I think your solution is the best one available at the moment, if you don't want to go deep into some android stuff and intercept all the motionEvent and TouchEvents yourself and then you also would need to trigger the pressed view of the button yourself etc.
Just create a nine patch image with a stretchable transparent border. In that way you can change the size of the image without the need to change the image itself and your button will grow or shrink without the actual displayed background changing.
Anothe idea is to make the new transparent image and put icon on it so the touch area will be more and design look perfect. Check out the image
Thank you.
Simply provide padding to the layout in place of Margin
<ImageView
android:id="#+id/back_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="25dip"
android:src="#drawable/back_btn" />
What I did is not the recommended way and very few will find it useful.
For me it was the best solution, because TouchDelegate did not worked in all View hierarchy scenarios.
The solution is based on overriding the hidden
View class
public boolean pointInView(float localX, float localY, float slop)
Here is the code:
public boolean pointInView(float localX, float localY, float slop) {
boolean res = ae_pointInView(localX, localY, slop, slop);
if(!res) {
if(viewIsClickableButToSmall(this)) {
//our view is clickable itself
float newSlopX = Math.max(slop, slop + minTouchableViewWidth - this.getWidth());
float newSlopY = Math.max(slop, slop + minTouchableViewHeight - this.getHeight());
if(ae_pointInView(localX, localY, newSlopX, newSlopY)) {
return true;
}
}
//the point is outside our view, now check for views with increased tap area that may extent beyond it
int childCount = getChildCount();
for(int i = 0; i < childCount;i++) {
View child = getChildAt(i);
if(child instanceof MyViewGroup) {
//this is our container that may also contain views with increased tap area
float[] newPoint = ae_transformPointToViewLocal(localX, localY, child);
if(((MyViewGroup) child).pointInView(newPoint[0], newPoint[1], slop)) {
return true;
}
}
else {
if(viewIsClickableButToSmall(child)) {
float[] newPoint = ae_transformPointToViewLocal(localX, localY, child);
float newSlopX = Math.max(slop, slop + minTouchableViewWidth - this.getWidth());
float newSlopY = Math.max(slop, slop + minTouchableViewHeight - this.getHeight());
if(ae_pointInView(newPoint[0], newPoint[1], newSlopX, newSlopY)) {
return true;
}
}
}
}
return false;
}
else
return true;
}
private int minTouchableViewHeight, minTouchableViewWidth;
private boolean viewIsClickableButToSmall(View view)
{
minTouchableViewHeight = GlobalHelper.dipToDevicePixels(40);
minTouchableViewWidth = GlobalHelper.dipToDevicePixels(40);
return (view.getHeight() < minTouchableViewHeight || view.getWidth() < minTouchableViewWidth) && view.hasOnClickListeners();
}
public boolean ae_pointInView(float localX, float localY, float slopX, float slopY) {
boolean res = localX >= -slopX && localY >= -slopY && localX < ((getRight() - getLeft()) + slopX) &&
localY < ((getBottom() - getTop()) + slopY);
return res;
}
private float[] tempPoint;
public float[] ae_transformPointToViewLocal(float x, float y, View child) {
if(tempPoint == null) {
tempPoint = new float[2];
}
tempPoint[0] = x + getScrollX() - child.getLeft();
tempPoint[1] = y + getScrollY() - child.getTop();
return tempPoint;
}
Maybe you could do so by looking at the X and Y coordinates of the MotionEvent passed into onTouchEvent ?

Categories

Resources