I know I'm not the first one having issue with a VerticalSlider on android but even though I recall struggling to make it work in the first place this is the first time that I have a partially working setProgress().
So here is the thing.
The blue line that represents the slider is properly updated but the tiny "button" that is supposed to moved as well does not move at all. (see images)
The blue line is moving according to to the values I send, but the "button" is not. It is moving a little, but not at all following the blue line---which is right. (If you have better terms for "button" and blue-line, feel free to edit. Progress line maybe?)
So this is the code I have for the vertical slider:
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.SeekBar;
public class VerticalSeekBar extends SeekBar {
public VerticalSeekBar(Context context) {
super(context);
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
}
#Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas canvas) {
canvas.rotate(-90);
canvas.translate(-getHeight(), 0);
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled())
return false;
boolean result = false;
if (event.getAction() != MotionEvent.ACTION_MOVE) {
// Prevent duplicate haptic feedback events (due to
// setProgress() below)
boolean hf = isHapticFeedbackEnabled();
setHapticFeedbackEnabled(false); {
// This is required for OnSeekBarChangeListener.on{Start,Stop}TrackingTouch()
result = super.onTouchEvent(event);
} setHapticFeedbackEnabled(hf);
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
// Vertical scrolling
setProgress(getMax() - (int)(getMax() * event.getY()/getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
result = true;
break;
}
return result;
}
public void customSetProgress(int progress) {
setProgress(progress);
onSizeChanged(getWidth(), getHeight(), 0, 0);
}
}
And this how I'm updating the slider:
float value = //... Get the value here from other computations
// We need to use int for the slider
final int step = 1;
final int max = (int)MAXPRECISION * 100;
final int min = (int)MINPRECISION * 100;
final double initialPosition = (double)max ;
final int valueInt = (int) (value * 100) ;
final VerticalSeekBar sliderPrecision = (VerticalSeekBar)findViewById(R.id.verticalSliderPrecision);
sliderPrecision.setProgress(valueInt);
sliderPrecision.setMax( (max - min) / step ); //To make sure it is updated as seen in some SO post.
I am pretty confident that my VerticalSlider class is good as I have been able to use it properly years ago. So there is surely something wrong with the rest of the code, but I can't find what that may be.
As for the images here they are:
So I found out that this is solved by calling onSizeChanged(getWidth(), getHeight(), 0, 0);
So I have created an updated VerticalSeekBar that works just fine now.
I do hope it will help other people struggling with them.
Here is the updated class:
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.SeekBar;
public class VerticalSeekBar extends SeekBar {
public VerticalSeekBar(Context context) {
super(context);
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
}
#Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas canvas) {
canvas.rotate(-90);
canvas.translate(-getHeight(), 0);
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled())
return false;
boolean result = false;
if (event.getAction() != MotionEvent.ACTION_MOVE) {
// Prevent duplicate haptic feedback events (due to
// setProgress() below)
boolean hf = isHapticFeedbackEnabled();
setHapticFeedbackEnabled(false); {
// This is required for OnSeekBarChangeListener.on{Start,Stop}TrackingTouch()
result = super.onTouchEvent(event);
} setHapticFeedbackEnabled(hf);
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
// Vertical scrolling
setProgress(getMax() - (int)(getMax() * event.getY()/getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
result = true;
break;
}
return result;
}
public void customSetProgress(int progress) {
setProgress(progress);
onSizeChanged(getWidth(), getHeight(), 0, 0);
}
}
Related
I created a CircularImageView with this question: Create circular image view in android
Download project on GitHub
1) This is the CircularImageView class :
public class CircularImageView extends ImageView {
public CircularImageView(Context context) {
super(context);
}
public CircularImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircularImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
if (getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap b = ((BitmapDrawable)drawable).getBitmap() ;
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
Bitmap roundBitmap = getCroppedBitmap(bitmap, getWidth());
canvas.drawBitmap(roundBitmap, 0, 0, null);
}
public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
Bitmap sbmp;
if(bmp.getWidth() != radius || bmp.getHeight() != radius)
sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false);
else
sbmp = bmp;
Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(), Bitmap.Config.ARGB_8888);
final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight());
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
paint.setColor(Color.parseColor("#BAB399"));
Canvas c = new Canvas(output);
c.drawARGB(0, 0, 0, 0);
c.drawCircle(sbmp.getWidth() / 2+0.7f, sbmp.getHeight() / 2+0.7f, sbmp.getWidth() / 2+0.1f, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
c.drawBitmap(sbmp, rect, rect, paint);
return output;
}
}
2) I use in my layout like this :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#cccccc"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp" >
<com.mikhaellopez.circularimageview.CircularImageView
android:id="#+id/imageViewCircular"
android:layout_width="#dimen/image_view_size"
android:layout_height="#dimen/image_view_size"
android:layout_gravity="center"
android:background="#drawable/border"
android:src="#drawable/image" />
</LinearLayout>
3) Current result in picture :
How do I change this code to have a shadow and a circular border around my imageView?
Objectif result :
Edit 10/15/2015 :
You can used or download my GitHub library CircularImageView with all the fixes by using gradle dependency :
compile 'com.mikhaellopez:circularimageview:2.0.1'
I modified the CircularImageView found here to achieve what you want.
To create a shadow around the border, I simply used these two lines:
this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
You need setLayerType due to hardware acceleration on HoneyComb and up. It didn't work without it when I tried it.
Here is the full code:
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class CircularImageView extends ImageView
{
private int borderWidth = 4;
private int viewWidth;
private int viewHeight;
private Bitmap image;
private Paint paint;
private Paint paintBorder;
private BitmapShader shader;
public CircularImageView(Context context)
{
super(context);
setup();
}
public CircularImageView(Context context, AttributeSet attrs)
{
super(context, attrs);
setup();
}
public CircularImageView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
setup();
}
private void setup()
{
// init paint
paint = new Paint();
paint.setAntiAlias(true);
paintBorder = new Paint();
setBorderColor(Color.WHITE);
paintBorder.setAntiAlias(true);
this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
}
public void setBorderWidth(int borderWidth)
{
this.borderWidth = borderWidth;
this.invalidate();
}
public void setBorderColor(int borderColor)
{
if (paintBorder != null)
paintBorder.setColor(borderColor);
this.invalidate();
}
private void loadBitmap()
{
BitmapDrawable bitmapDrawable = (BitmapDrawable) this.getDrawable();
if (bitmapDrawable != null)
image = bitmapDrawable.getBitmap();
}
#SuppressLint("DrawAllocation")
#Override
public void onDraw(Canvas canvas)
{
// load the bitmap
loadBitmap();
// init shader
if (image != null)
{
shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvas.getWidth(), canvas.getHeight(), false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
int circleCenter = viewWidth / 2;
// circleCenter is the x or y of the view's center
// radius is the radius in pixels of the cirle to be drawn
// paint contains the shader that will texture the shape
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, circleCenter + borderWidth - 4.0f, paintBorder);
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, circleCenter - 4.0f, paint);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec, widthMeasureSpec);
viewWidth = width - (borderWidth * 2);
viewHeight = height - (borderWidth * 2);
setMeasuredDimension(width, height);
}
private int measureWidth(int measureSpec)
{
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY)
{
// We were told how big to be
result = specSize;
}
else
{
// Measure the text
result = viewWidth;
}
return result;
}
private int measureHeight(int measureSpecHeight, int measureSpecWidth)
{
int result = 0;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY)
{
// We were told how big to be
result = specSize;
}
else
{
// Measure the text (beware: ascent is a negative number)
result = viewHeight;
}
return (result + 2);
}
}
I hope it helps!
.
EDIT
I forked your CircularImageView and added support for selector overlays. I also improved drawing performance significantly...
https://github.com/Pkmmte/CircularImageView
To add a border by making ImageView as a circle, i've done a simple thing, I used this class to make my image as a circle
package com.fidenz.fexceller.fexceller;
/**
* Created by Chathu Hettiarachchi on 5/18/2015.
*/
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
public class RoundedImg extends Drawable {
private final Bitmap mBitmap;
private final Paint mPaint;
private final RectF mRectF;
private final int mBitmapWidth;
private final int mBitmapHeight;
public RoundedImg(Bitmap bitmap) {
mBitmap = bitmap;
mRectF = new RectF();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
final BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(shader);
mBitmapWidth = mBitmap.getWidth();
mBitmapHeight = mBitmap.getHeight();
}
#Override
public void draw(Canvas canvas) {
canvas.drawOval(mRectF, mPaint);
}
#Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mRectF.set(bounds);
}
#Override
public void setAlpha(int alpha) {
if (mPaint.getAlpha() != alpha) {
mPaint.setAlpha(alpha);
invalidateSelf();
}
}
#Override
public void setColorFilter(ColorFilter cf) {
mPaint.setColorFilter(cf);
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
#Override
public int getIntrinsicWidth() {
return mBitmapWidth;
}
#Override
public int getIntrinsicHeight() {
return mBitmapHeight;
}
public void setAntiAlias(boolean aa) {
mPaint.setAntiAlias(aa);
invalidateSelf();
}
#Override
public void setFilterBitmap(boolean filter) {
mPaint.setFilterBitmap(filter);
invalidateSelf();
}
#Override
public void setDither(boolean dither) {
mPaint.setDither(dither);
invalidateSelf();
}
public Bitmap getBitmap() {
return mBitmap;
}
}
and by using this on onCreate i have call the image for setting it,
profilePic = (ImageView)findViewById(R.id.img_home_profile_pic);
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.no_image);
roundedImage = new RoundedImg(bm);
profilePic.setImageDrawable(roundedImage);
to add a border i created a circle shape XML like this,
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
<gradient android:startColor="#color/ring_color" android:endColor="#color/ring_color"
android:angle="270"/>
</shape>
then using layouts i added a RelativeLayout with ImageView inside of it, by using padding and background drawable with wrap_content i set my RelativeLayout like this
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/lay_rel_img"
android:layout_gravity="center"
android:padding="5dp"
android:background="#drawable/circle">
<ImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center"
android:id="#+id/img_home_profile_pic"
android:src="#drawable/no_image"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
now it show like this, i don't know to add the shadow, sorry for that too
Add
canvas.drawCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2, paint);
before
canvas.drawBitmap(roundBitmap, 0, 0, null);
Change
c.drawCircle(sbmp.getWidth() / 2, sbmp.getHeight() / 2, sbmp.getWidth() / 2, paint);
to
c.drawCircle(sbmp.getWidth() / 2, sbmp.getHeight() / 2, sbmp.getWidth() / 2 - "the border with you prefer", paint);
Hope it helps.
Maybe a better solution here.
Create a custom drawable, and use that to define your the background attribute of your ImageView. You can use a LayeredDrawable, to create as many different components for the component as you would like.
Checkout this answer, which creates a custom Rectangle (but is exactly the same with an Oval\Circle): How to create Google + cards UI in a list view?
I found a library that doing exactly what you wish, worked fine for me.
Check it out.
https://android-arsenal.com/details/1/932
just use drawCircle() method with more width and height before drawing the actual image. Increase the width and height of in that new method call according to your wish, and set some another color of you want on paint
This Class is Custom Circular Imageview with shadow, Stroke,saturation and using this Custom Circular ImageView you can make your image in Circular Shape with Radius. Guys for Circular Shadow ImageView No need Github this class is enough.
Adding CircularImageView to your layout
// Bitmap myimage=BitmapFactory.decodeResource(getResources(),R.drawable.pic);
CircularImageView c=new CircularImageView(this,screen width,screen height,Bitmap myimage);
yourLayout.addView(c);**
public class CircularImageView extends android.support.v7.widget.AppCompatImageView
{
private final Context context;
private final int width, height;
private final Paint paint;
private final Paint paintBorder,imagePaint;
private final Bitmap bitmap2;
private final Paint paint3;
private Bitmap bitmap;
private BitmapShader shader;
private float radius = 4.0f;
float x = 0.0f;
float y = 8.0f;
private float stroke;
private float strokeWidth = 0.0f;
private Bitmap bitmap3;
private int corner_radius=50;
public CircularImageView(Context context, int width, int height, Bitmap bitmap) {
super(context);
this.context = context;
this.width = width;
this.height = height;
//here "bitmap" is the square shape(width* width) scaled bitmap ..
this.bitmap = bitmap;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
paint3=new Paint();
paint3.setStyle(Paint.Style.STROKE);
paint3.setColor(Color.WHITE);
paint3.setAntiAlias(true);
paintBorder = new Paint();
imagePaint= new Paint();
paintBorder.setColor(Color.WHITE);
paintBorder.setAntiAlias(true);
this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
this.bitmap2 = Bitmap.createScaledBitmap(bitmap, (bitmap.getWidth() - 40), (bitmap.getHeight() - 40), true);
imagePaint.setAntiAlias(true);
invalidate();
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Shader b;
if (bitmap3 != null)
b = new BitmapShader(bitmap3, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
else
b = new BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
imagePaint.setShader(b);
canvas.drawBitmap(maskedBitmap(), 20, 20, null);
}
private Bitmap maskedBitmap()
{
Bitmap l1 = Bitmap.createBitmap(width,width, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(l1);
paintBorder.setShadowLayer(radius, x, y, Color.parseColor("#454645"));
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
final RectF rect = new RectF();
rect.set(20, 20, bitmap2.getWidth(), bitmap2.getHeight());
canvas.drawRoundRect(rect, corner_radius, corner_radius, paintBorder);
canvas.drawRoundRect(rect, corner_radius, corner_radius, imagePaint);
if (strokeWidth!=0.0f)
{
paint3.setStrokeWidth(strokeWidth);
canvas.drawRoundRect(rect, corner_radius, corner_radius, paint3);
}
paint.setXfermode(null);
return l1;
}
// use seekbar here, here you have to pass "0 -- 250" here corner radius will change
public void setCornerRadius(int corner_radius)
{
this.corner_radius = corner_radius;
invalidate();
}
-------->use seekbar here, here you have to pass "0 -- 10.0f" here shadow radius will change
public void setShadow(float radius)
{
this.radius = radius;
invalidate();
}
// use seekbar here, here you have to pass "0 -- 10.0f" here stroke size will change
public void setStroke(float stroke)
{
this.strokeWidth = stroke;
invalidate();
}
private Bitmap updateSat(Bitmap src, float settingSat)
{
int w = src.getWidth();
int h = src.getHeight();
Bitmap bitmapResult =
Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvasResult = new Canvas(bitmapResult);
Paint paint = new Paint();
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(settingSat);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix);
paint.setColorFilter(filter);
canvasResult.drawBitmap(src, 0, 0, paint);
return bitmapResult;
}
// use seekbar here, here you have to pass "0 -- 2.0f" here saturation will change
public void setSaturation(float sat)
{
System.out.println("qqqqqqqqqq "+sat);
bitmap3=updateSat(bitmap2, sat);
invalidate();
}
}
// Seekbar to change radius
radius_seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
text_radius.setText(""+progress);
circularImageView.setCornerRadius(progress);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
// Seekbar to change shadow
shadow_seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
float f= 4+progress/10.0f;
text_shadow.setText(""+progress);
circularImageView.setShadow(f);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
// Seekbar to change saturation
saturation_seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
int progressSat = saturation_seekbar.getProgress();
float sat = (float) ((progressSat*4 / 100.0f)-1.0f);
circularImageView.setSaturation(sat);
text_saturation.setText(""+progressSat);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
// Seekbar to change stroke
stroke_seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
if (progress==0)
{
float f=(progress*10.0f/100.0f);
circularImageView.setStroke(f);
}
else
{
float f=(progress*10.0f/100.0f);
circularImageView.setStroke(f);
}
text_stroke.setText(""+progress);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
//radius seekbar in xml file
<SeekBar
android:layout_width="match_parent"
android:layout_gravity="center"
android:progress="50"
android:max="250"
android:id="#+id/radius_seekbar"
android:layout_height="wrap_content" />
//saturation seekbar in xml file
<SeekBar
android:layout_width="match_parent"
android:layout_gravity="center"
android:progress="50"
android:max="100"
android:id="#+id/saturation_seekbar"
android:layout_height="wrap_content" />
//shadow seekbar in xml file
<SeekBar
android:layout_width="match_parent"
android:layout_gravity="center"
android:progress="0"
android:max="100"
android:id="#+id/shadow_seekbar"
android:layout_height="wrap_content" />
//stroke seekbar in xml file
<SeekBar
android:layout_width="match_parent"
android:layout_gravity="center"
android:progress="0"
android:max="100"
android:id="#+id/stroke _seekbar"
android:layout_height="wrap_content" />
I am trying to create a subclass of Button. The code is as below
package com.comnet.bookshelf;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Button;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
public class myButton extends Button implements OnClickListener{
Paint mainPaint;
int colorArray[];
int colorArrayAlt[];
boolean touch=false;
Rect bound;
public myButton(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
mainPaint=new Paint();
bound=new Rect();
defaultColorIndexArray();
}
public myButton(Context context, AttributeSet attrs)
{
super(context, attrs);
mainPaint=new Paint();
bound=new Rect();
defaultColorIndexArray();
}
public myButton(Context context)
{
super(context);
mainPaint=new Paint();
bound=new Rect();
defaultColorIndexArray();
}
private void defaultColorIndexArray(){
colorArray=new int[]{
0xFFd28181, //1
0xFFd48787, //2
0xFFd68d8d, //3
0xFFd89292, //4
0xFFda9898, //5
0xFFdc9e9e, //6
0XFFdea2a2, //7
0XFFe0a8a8, //8
0xFFe2adad, //9
0XFFe3b1b1, //10
0XFFe4b4b4, //11
0XFFe6b9b9, //12
0XFFe7bdbd, //13
0XFFe9c0c0, //14
0XFFeac3c3, //15
0XFFebc6c6, //16
0XFFebc7c7, //17
0XFFecc9c9, //18
0XFFeccaca, //19
0XFFeccaca, //20
0XFFeccbcb, //21
0XFFeccbcb //22
};
colorArrayAlt=new int[]{
0XFFeccbcb, //22
0XFFeccbcb, //21
0XFFeccaca, //20
0XFFeccaca, //19
0XFFecc9c9, //18
0XFFebc7c7, //17
0XFFebc6c6, //16
0XFFeac3c3, //15
0XFFe9c0c0, //14
0XFFe7bdbd, //13
0XFFe6b9b9, //12
0XFFe4b4b4, //11
0XFFe3b1b1, //10
0xFFe2adad, //9
0XFFe0a8a8, //8
0XFFdea2a2, //7
0xFFdc9e9e, //6
0xFFda9898, //5
0xFFd89292, //4
0xFFd68d8d, //3
0xFFd48787, //2
0xFFd28181 //1
};
}
public void setButtonColorIndexArray(int carray[], int carray_alt[]){
}
#Override
protected void onDraw(Canvas canvasObject) {
super.onDraw(canvasObject);
int draw_color[];
if(touch==false)
draw_color=colorArray;
else
draw_color=colorArrayAlt;
int width=canvasObject.getWidth();
int height=canvasObject.getHeight();
double colorcount=44;
double divheight=height;
double f=colorcount/divheight;
double step=0;
for(int i=0;i<height;i++,step+=f){
int next=(int) Math.round(step);
if(next>43) next=43;
else if(next<0)next=0;
if(next<22){
mainPaint.setColor(draw_color[next]);
canvasObject.drawLine(0, i, width, i, mainPaint);
}
else{
mainPaint.setColor(draw_color[43-next]);
canvasObject.drawLine(0, i, width, i, mainPaint);
}
//int color=;
mainPaint.setColor(getCurrentTextColor());
String str=this.getText().toString();
//mainPaint.setColor(Color.WHITE);
mainPaint.setStyle(Style.FILL);
//canvasObject.drawPaint(mainPaint);
mainPaint.setColor(Color.BLACK);
mainPaint.setTextSize(20);
mainPaint.getTextBounds(str, 0, str.length(), bound);
int x=(width-(bound.right-bound.left))/2;
int y=(height+(bound.bottom-bound.top))/2;
canvasObject.drawText(str, x, y, mainPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent ev){
if(ev.getAction()==MotionEvent.ACTION_DOWN){
//Log.i("Click", "ACTION_DOWN");
touch=true;
this.invalidate();
}
else if(ev.getAction()==MotionEvent.ACTION_UP){
touch=false;
this.invalidate();
}
return true;
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i("Clicked", "Clicked");
}
}
Everything but one is working as I expected.
onClick is not responding at all. The code is as below:
((myButton)inflatedLayout.findViewById(R.id.DeleteButton)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
DeleteTheEntireBook();
}
});
The button with default class is working fine
If you have any further question, let me know.
The problem is You have overridden onTouchEvent.
Mark these words:
You should return false in your OnTouchListener then your OnClickListener will be also handled.
So you might think, I will just do my thing there and return false so I can receive clicks too. If you do so, it will work, but you wont be subscribed to other upcoming touch events (ACTION_MOVE, ACTION_UP) Therefore only option is to return true there, but then you wont receive any click events as we said previously.
So you need to perform the click manually in the ACTION_UP with performClick()
Tested and working code :
#Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
// Log.i("Click", "ACTION_DOWN");
touch = true;
this.invalidate();
} else if (ev.getAction() == MotionEvent.ACTION_UP) {
touch = false;
this.invalidate();
// KEY LINE
performClick();
}
return true;
}
Hope it helps ツ
in the constructor, add the onClickListener,
and no need to ((myButton)inflatedLayout.findViewB...
public myButton(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
mainPaint=new Paint();
bound=new Rect();
defaultColorIndexArray();
setOnClickListener(this);
}
then the overridden onClick in myButton class should be called once the button is clicked.
View.OnClickListener :Interface definition for a callback to be invoked when a view is clicked.
Can you use this Code:
((myButton)inflatedLayout.findViewById(R.id.DeleteButton)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DeleteTheEntireBook();
}
});
I'm developing a news application, I want to use a breaking news banner at the bottom of the layout.
The layout is :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:gravity="bottom">
<com.example.test.ScrollTextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20dp"
android:background="#00ff00"
android:id="#+id/scrolltext">
</com.example.test.ScrollTextView>
</LinearLayout>
And the Java code is :
package com.example.test;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Color;
import android.os.Build;
import android.os.Handler;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.TranslateAnimation;
import android.widget.*;
import java.util.Map;
public class Newstest extends Activity
{
TextView label1;
#Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.news);
ScrollTextView scrolltext=(ScrollTextView) findViewById(R.id.scrolltext);
scrolltext.setText("dddddddddddddddddddddddddddddddddd sajd asjd lksdddddddddddddddddddddddddddddddddd sajd asjd lksdddddddddddddddddddddddddddddddddd sajd asjd lksdddddddddddddddddddddddddddddddddd sajd asjd lks");
scrolltext.setTextColor(Color.BLACK);
scrolltext.startScroll();
}
}
I'm using a ScrollTextView class :
package com.example.test;
import android.content.Context;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.animation.LinearInterpolator;
import android.widget.Scroller;
import android.widget.TextView;
public class ScrollTextView extends TextView {
// scrolling feature
private Scroller mSlr;
// milliseconds for a round of scrolling
private int mRndDuration = 10000;
// the X offset when paused
private int mXPaused = 0;
// whether it's being paused
private boolean mPaused = true;
/*
* constructor
*/
public ScrollTextView(Context context) {
this(context, null);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}
/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}
/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}
/**
* begin to scroll the text from the original position
*/
public void startScroll() {
// begin from the very right side
mXPaused = -1 * getWidth();
// assume it's paused
mPaused = true;
resumeScroll();
}
/**
* resume the scroll from the pausing point
*/
public void resumeScroll() {
if (!mPaused)
return;
// Do not know why it would not scroll sometimes
// if setHorizontallyScrolling is called in constructor.
setHorizontallyScrolling(true);
// use LinearInterpolator for steady scrolling
mSlr = new Scroller(this.getContext(), new LinearInterpolator());
setScroller(mSlr);
int scrollingLen = calculateScrollingLen();
int distance = scrollingLen - (getWidth() + mXPaused);
int duration = (new Double(mRndDuration * distance * 1.00000
/ scrollingLen)).intValue();
setVisibility(VISIBLE);
mSlr.startScroll(mXPaused,0, distance, 0, duration);
invalidate();
mPaused = false;
}
/**
* calculate the scrolling length of the text in pixel
*
* #return the scrolling length in pixels
*/
private int calculateScrollingLen() {
TextPaint tp = getPaint();
Rect rect = new Rect();
String strTxt = getText().toString();
tp.getTextBounds(strTxt, 0, strTxt.length(), rect);
int scrollingLen = rect.width() + getWidth();
rect = null;
return scrollingLen;
}
/**
* pause scrolling the text
*/
public void pauseScroll() {
if (null == mSlr)
return;
if (mPaused)
return;
mPaused = true;
// abortAnimation sets the current X to be the final X,
// and sets isFinished to be true
// so current position shall be saved
mXPaused = mSlr.getCurrX();
mSlr.abortAnimation();
}
#Override
/*
* override the computeScroll to restart scrolling when finished so as that
* the text is scrolled forever
*/
public void computeScroll() {
super.computeScroll();
if (null == mSlr) return;
if (mSlr.isFinished() && (!mPaused)) {
this.startScroll();
}
}
public int getRndDuration() {
return mRndDuration;
}
public void setRndDuration(int duration) {
this.mRndDuration = duration;
}
public boolean isPaused() {
return mPaused;
}
}
What I want is that the text will scroll from left to right, the opposite of what the class does. I tried changing parameters in the line mSlr.startScroll(mXPaused,0, distance, 0, duration); but the scrolling direction remains the same. Any help please
Have you tried marquee attribute? This should scroll text that doesn't fit the view
<TextView
android:layout_width="10dip"
android:layout_height="wrap_content"
android:text="FooBar FooBar FooBar FooBar"
android:singleLine="true"
android:ellipsize="marquee" />
http://developer.android.com/reference/android/widget/TextView.html#attr_android:ellipsize
From looking at the API docs:
http://developer.android.com/reference/android/widget/Scroller.html#startScroll(int, int, int, int)
Seems you can pass it negative numbers to scroll the opposite way, so try:
mSlr.startScroll(mXPaused, 0, -distance, 0, duration);
Marquee attribute only works for focused views, so use this view instead of textview beside android:ellipsize="marquee":
public class TextViewMarquee extends TextView
{
public TextViewMarquee(Context context, AttributeSet attrs)
{
super(context, attrs, R.attr.marqueeStyle);
}
public TextViewMarquee(Context context, AttributeSet attrs, int style)
{
super(context, attrs, style);
}
#Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect)
{
if(focused) super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
#Override
public void onWindowFocusChanged(boolean focused)
{
if(focused) super.onWindowFocusChanged(focused);
}
#Override
public boolean isFocused()
{
return true;
}
}
I find myself in need of assistance.
I'm trying to develop this simple app that takes pictures (Wow, now that's original!). Everything is fine. The only thing I need is to have a CIRCULAR CAMERA PREVIEW.
I have my camerapreview class (which extends surfaceview) placed inside a frame layout, which is my camera preview basically. As you all know, this comes in a rectangular shape. Since I have bigger plans for the app, I'd need the camera preview to be circular (so, for example, someone can take a picture of someone's face and I can have some drawings around...).
Now, I don't know how to proceed. I tried different things, creating a shape with xml and set it as background for my frame layout, but that just didn't work.
After hours spent on google for solutions I decided that I had to give up and come here.
So please, if someone knows anything, let us know :) I hope I was clear enough, do not hesitate to ask for clarification if needed.
Simple way:
1) not setup surface for priview
2) catch raw data
3) convert to bitmap and make circle
4) show (for ex. on imegeview)
just for sample:
public class CameraRoundPriview extends ImageView {
private Camera camera;
private Bitmap bitmap = null;
private int mPreviewWidth, mPreviewHeight;
boolean mCameraOn = false;
public CameraRoundPriview(Context context, AttributeSet attrs) {
super(context, attrs);
}
private Bitmap getclip() {
//clip
Bitmap output = Bitmap.createBitmap(bitmap.getHeight(),
bitmap.getHeight(),
Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getHeight(),
bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawCircle(bitmap.getHeight() / 2,
bitmap.getHeight() / 2,
bitmap.getHeight() / 2, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
//rotate
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(getCameraID(), info);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result = degrees;
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP){
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
}
Matrix matrix = new Matrix();
matrix.postRotate(result);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(output,output.getWidth(),output.getHeight(),true);
Bitmap rotatedBitmap = Bitmap.createBitmap(scaledBitmap , 0, 0, scaledBitmap.getWidth(), scaledBitmap .getHeight(), matrix, true);
return rotatedBitmap;
}
private void showImage(){
if ((bitmap != null)){
this.setImageBitmap(getclip());
}
}
public boolean onClickCamera(){
if (mCameraOn){
mCameraOn = false;
cameraStop();
}else{
mCameraOn = true;
cameraStart();
}
return mCameraOn;
}
private void cameraStop(){
if (camera == null) return;
camera.setPreviewCallback(null);
camera.release();
camera = null;
}
private int getCameraID(){
// specify camera id
return 0;
}
private void cameraStart(){
Camera camera = Camera.open(getCameraID());
final Camera.Size previewSize = camera.getParameters().getPreviewSize();
mPreviewWidth = previewSize.width;
mPreviewHeight = previewSize.height;
try {
camera.setPreviewCallback(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera_call) {
ByteArrayOutputStream outstr = new ByteArrayOutputStream();
Rect rect = new Rect(0, 0, mPreviewWidth, mPreviewHeight);
YuvImage yuvimage=new YuvImage(data,ImageFormat.NV21,mPreviewWidth,mPreviewHeight,null);
yuvimage.compressToJpeg(rect, 50, outstr);
bitmap = BitmapFactory.decodeByteArray(outstr.toByteArray(), 0, outstr.size());
showImage();
camera_call.addCallbackBuffer(data);
}
});
} catch (Exception e) {}
camera.startPreview();
this.camera=camera;
}
}
You can overlay an ImageView over the camera preview. put both the SurfaceView and the ImageView within a FrameLayout both match_parent and the image must be on top.
Set to an black image with transparent circle in the middle.
this is as simple as shown below:
this is for camerax or camera2 API
Note: you must have background transparent.
you must have xml file like below.
<com.RoundedCameraPreview
android:id="#+id/viewFinder"
android:background="#00000000"
app:scaleType="fillCenter"
android:layout_width="match_parent"
android:layout_height="match_parent" />
also don't forget to declare in style.xml
<declare-styleable name="PreviewView">
<attr name="isRound" format="boolean" />
</declare-styleable>
and code is written like this
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.view.PreviewView;
public class RoundedCameraPreview extends PreviewView {
Path clipPath;
boolean isRound;
public RoundedCameraPreview(#NonNull Context context) {
super(context);
}
public RoundedCameraPreview(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public RoundedCameraPreview(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.PreviewView,
0, 0);
try {
isRound = a.getBoolean(R.styleable.PreviewView_isRound, true);
} finally {
a.recycle();
}
}
public boolean isRound() {
return isRound;
}
public void setIsRound(boolean isRound) {
this.isRound = isRound;
invalidate();
requestLayout();
}
public RoundedCameraPreview(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
protected void dispatchDraw(Canvas canvas) {
if (isRound) {
clipPath = new Path();
//TODO: define the circle you actually want
clipPath.addCircle(canvas.getWidth() / 2, canvas.getWidth() / 2, canvas.getWidth() / 2, Path.Direction.CW);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.clipPath(clipPath);
canvas.drawPath(clipPath, paint);
}
super.dispatchDraw(canvas);
}
}
Using onDraw, I want to make a custom text view that changes color depending on its text value. For example, if the text value is "hello" I want it to be red and if it says "bye" I want it to be green. Any helps greatly appreciated.
I'm not necessarily sure why you want to do this in onDraw(). Unless you have a really good reason to set up a custom TextView/EditText, that's not necessary.
To simplify your situation, you can implement a TextWatcher to do this, and in onTextChanged(), you can set the color by comparing the string values using .equals().
Here is an example of your theoretical situation:
final EditText yourEditText = /* findViewById maybe? */;
yourEditText.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.equalsIgnoreCase("hello"))
yourEditText.setTextColor(Color.RED);
else if (s.equalsIgnoreCase("bye"))
yourEditText.setTextColor(Color.GREEN);
else // if it says neither "hello" nor "bye"
yourEditText.setTextColor(Color.BLACK);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Nothing needs to happen here
}
public void afterTextChanged(Editable s) {
// Nothing needs to happen here
}
});
If you feel its necessary to maintain this in onDraw(), simply extract the code from onTextChanged() and change yourEditText to this, or place it in the constructor instead:
public class YourTextView extends TextView { // Or extends EditText, doesn't matter
public YourTextView(Context context) {
this(context, null, 0);
}
public YourTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public YourTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
addTextChangedListener(new TextWatcher() {
// Copy the TextWatcher code from the example above, replacing "yourEditText" with "YourTextView.this"
});
}
// ... Rest of your class
}
I figured out how to do it in a more creative way using onDraw.
public class MagnitudeTextView extends TextView {
public MagnitudeTextView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public MagnitudeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public MagnitudeTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
/*
* (non-Javadoc)
*
* #see android.widget.TextView#onDraw(android.graphics.Canvas)
*/
#Override
protected void onDraw(Canvas canvas) {
int height = getMeasuredHeight();
int width = getMeasuredWidth();
int px = width / 2;
int py = height / 2;
Paint Red = new Paint(Paint.ANTI_ALIAS_FLAG);
Red.setColor(Color.RED);
Paint White = new Paint(Paint.ANTI_ALIAS_FLAG);
White.setColor(Color.DKGRAY);
Paint Yellow = new Paint(Paint.ANTI_ALIAS_FLAG);
Yellow.setARGB(210, 105, 30, 0);
Paint Blue = new Paint(Paint.ANTI_ALIAS_FLAG);
Blue.setColor(Color.BLUE);
float textWidth = Red.measureText(String.valueOf(getText()));
String g = String.valueOf(getText());
if (g.startsWith("3") || g.startsWith("4")) {
canvas.drawText(String.valueOf(getText()), px - textWidth / 2, py,
White);
}
if (g.startsWith("6") || g.startsWith("5") || g.startsWith("7")
|| g.startsWith("8")) {
canvas.drawText(String.valueOf(getText()), px - textWidth / 2, py,
Yellow);
}
if (g.startsWith("9") || g.startsWith("10")) {
canvas.drawText(String.valueOf(getText()), px - textWidth / 2, py,
Red);
}
// super.onDraw(canvas);
}
}
You can overwrite setText() and set the color using setTextColor().
You can do it inside onDraw as well, but it's not worth the weigth, as it may pass many times inside onDraw.
You can implement TextWatcher and use onTextChanged()
More about it here in the Android Docs
Use this to get the text:
TextView text = (TextView)findViewById(R.id.textid);
String value = text.getText().toString();
Then check what the text is and change the color :
if (value.equals("hello")) {
text.setBackgroundColor(yourcolor);
}