when i use android:progressDrawable="#drawable/barcolor",it works properly, but when i use setProgressDrawable, it looks wrong
my layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ProgressBar
android:id="#+id/firstProgressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="300dip"
android:layout_height="30dip"
android:layout_centerHorizontal="true"
android:layout_above="#+id/text_first"
android:max="300"
android:progress="0" />
<TextView
android:id="#+id/text_first"
android:textColor="#fff"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp"
android:gravity="center"
/>
</RelativeLayout>
and my java codes:
firstProgressBar = (ProgressBar)findViewById(resId4);
resId = getResources().getIdentifier("barcolor","drawable",packageName);
Rect bounds = firstProgressBar.getProgressDrawable().getBounds();
firstProgressBar.setProgressDrawable(getResources().getDrawable(resId));
firstProgressBar.getProgressDrawable().setBounds(bounds);
and the barcolor.xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<nine-patch android:src="#drawable/progress_bar_bg">
</nine-patch>
</item>
<item android:id="#android:id/progress">
<clip>
<nine-patch android:src="#drawable/progress_bar">
</nine-patch>
</clip>
</item>
</layer-list>
thank you all !
Try this:
firstProgressBar.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect bounds = firstProgressBar.getProgressDrawable().getBounds();
Drawable drawable = getResources().getDrawable(resId);
drawable.setBounds(bounds);
firstProgressBar.setProgressDrawable(drawable);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
firstProgressBar.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
firstProgressBar.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
});
hoomi, thank you for your help! I have solved this problem with custom ProgressBar, it calls CustomPorgressBar:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
import android.widget.ProgressBar;
public class CustomProgressBar extends ProgressBar {
public CustomProgressBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomProgressBar(Context context) {
super(context);
}
#Override
public void draw(Canvas canvas) {
Drawable d = getProgressDrawable();
if (d instanceof LayerDrawable) {
LayerDrawable layerDrawable = (LayerDrawable) d;
Drawable progressDrawable = layerDrawable
.findDrawableByLayerId(android.R.id.progress);
//
layerDrawable.setBounds(0, 0, progressRight, progressBottom);
progressDrawable.setBounds(0, 0, progressRight, progressBottom);
}
super.draw(canvas);
}
private int progressRight;
private int progressBottom;
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
progressRight = getWidth() - getPaddingRight() - getPaddingLeft();
progressBottom = getHeight() - getPaddingBottom() - getPaddingTop();
}
}
Related
This question already has answers here:
How to draw a vertical line in "android Horizontal Progress bar"
(3 answers)
Closed 2 years ago.
While developing Android, there was a task that required to put a dividing line in the Progress Bar as shown in the following figure.
But the Progress Bar I implemented is as follows.
The progress bar I made consists of the following code.
<?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 android:shape="rectangle">
<solid android:color="#D1D1D6" />
<size android:height="20dp" />
<corners android:radius="12dp" />
</shape>
</item>
<item android:id="#android:id/progress">
<clip>
<shape android:shape="rectangle">
<solid android:color="#26B477" />
<size android:height="20dp" />
<corners android:radius="12dp" />
</shape>
</clip>
</item>
</layer-list>
The custom_seekbar.xml in the drawable file implemented as above was used as follows.
<ProgressBar
style="#style/Widget.AppCompat.ProgressBar.Horizontal"
android:id="#+id/todayGage"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_marginStart="12dp"
android:layout_marginLeft="12dp"
android:layout_marginEnd="25dp"
android:layout_marginRight="25dp"
android:max="100"
android:paddingStart="0dp"
android:paddingLeft="0dp"
android:paddingEnd="0dp"
android:paddingRight="0dp"
android:progressDrawable="#drawable/custom_seekbar"
app:layout_constraintBottom_toBottomOf="#id/todayPercent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#id/todayPercent"
app:layout_constraintTop_toTopOf="#id/todayPercent" />
Is there a way to put a dividing line inside the Progress Bar like I want??
Hello hanjiman
I will suggest you with two example
First One
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.widget.ProgressBar;
public class MainLayout extends Activity {
int progress=1;
ProgressBar progressBar;
#SuppressLint("ResourceType")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar= (ProgressBar)findViewById(R.id.progress_bar_test);
SeperatedProgressbar bgProgress= new SeperatedProgressbar(ContextCompat.getColor(this,R.color.color_progress),ContextCompat.getColor(this,R.color.color_normal),this);
progressBar.setProgressDrawable(bgProgress);
progressBar.setMax(100);
progressBar.setProgress(50);
new CountDownTimer(100000, 1000) {
public void onTick(long millisUntilFinished) {
progress=progress+1;
progressBar.setProgress(progress);
}
public void onFinish() {
}
}.start();
}
}
activity_main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:paddingLeft="10dp"
android:layout_height="match_parent"
>
<ProgressBar
android:id="#+id/progress_bar_test"
android:layout_width="match_parent"
android:layout_height="25dp"
android:layout_centerInParent="true"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:progress="10"
/>
</RelativeLayout>
SeperatedProgressbar.java
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
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.drawable.Drawable;
public class SeperatedProgressbar extends Drawable {
private static final int NUM_SEGMENTS = 8;
private int mForeground;
private int mBackground;
private final Paint mPaint = new Paint();
private final RectF mSegment = new RectF();
Context context;
public SeperatedProgressbar(int fgColor, int bgColor, Context context) {
mForeground = fgColor;
this.context=context;
mBackground = bgColor;
}
#Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
#Override
public void draw(Canvas canvas) {
float level = getLevel() / 1000f;
Rect b = getBounds();
float gapWidth = b.height() / 8f;
float segmentWidth = (b.width() - (NUM_SEGMENTS - 1) * gapWidth) / NUM_SEGMENTS;
mSegment.set(0, 0, segmentWidth, b.height());
mPaint.setColor(mForeground);
for (int i = 0; i < NUM_SEGMENTS; i++) {
float loLevel = i / (float) NUM_SEGMENTS;
float hiLevel = (i + 1) / (float) NUM_SEGMENTS;
if (loLevel <= level && level <= hiLevel) {
float middle = mSegment.left + NUM_SEGMENTS * segmentWidth * (level - loLevel);
canvas.drawRect(mSegment.left, mSegment.top, middle, mSegment.bottom, mPaint);
mPaint.setColor(mBackground);
canvas.drawRect(middle, mSegment.top, mSegment.right, mSegment.bottom, mPaint);
} else {
canvas.drawRect(mSegment, mPaint);
}
mSegment.offset(mSegment.width() + gapWidth, 0);
}
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter cf) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
Result
Second Answer
MainActivity.Java
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import com.rachitgoyal.segmented.SegmentedProgressBar;
import java.util.ArrayList;
import java.util.Arrays;
public class MainActivity extends AppCompatActivity {
SegmentedProgressBar mSegmentedProgressBar;
ArrayList<Integer> arrayList=new ArrayList<>();;
int progress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSegmentedProgressBar = findViewById(R.id.segmented_pb_1);
arrayList.add(progress);
new CountDownTimer(200000, 2000) {
public void onTick(long millisUntilFinished) {
if(progress==0)
{
arrayList.add(progress);
}
else
{
arrayList.add(progress);
}
progress=progress+1;
mSegmentedProgressBar.setEnabledDivisions(arrayList);
}
public void onFinish() {
}
}.start();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.test.package.SegmentedProgressBar
android:id="#+id/segmented_pb_1"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_centerHorizontal="true"
android:layout_margin="10dp"
android:layout_centerInParent="true"
app:cornerRadius="20dp"
app:dividerColor="#color/white"
app:dividerWidth="2dp"
app:divisions="10"
app:isDividerEnabled="true"
app:progressBarBackgroundColor="#dadada"
app:progressBarColor="#ff2d2d" />
</RelativeLayout>
SegmentedProgressBar.java
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import com.test.package.segmentedprogressbar.R;
import java.util.ArrayList;
import java.util.List;
public class SegmentedProgressBar extends View {
private static final String TAG = "SegmentedProgressBar";
RectF bgRect;
private Paint progressBarBackgroundPaint = new Paint();
private Paint progressBarPaint = new Paint();
private Paint dividerPaint = new Paint();
private int progressBarWidth;
private float percentCompleted;
private float dividerWidth = 1;
private boolean isDividerEnabled = true;
private int divisions = 1;
private List<Integer> enabledDivisions = new ArrayList<>();
private List<Float> dividerPositions;
private float cornerRadius = 20f;
public SegmentedProgressBar(Context context) {
super(context);
init(null);
}
private void init(AttributeSet attrs) {
dividerPositions = new ArrayList<>();
cornerRadius = 0;
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.SegmentedProgressBar, 0, 0);
try {
dividerPaint.setColor(typedArray.getColor(R.styleable.SegmentedProgressBar_dividerColor,
ContextCompat.getColor(getContext(), R.color.white)));
progressBarBackgroundPaint.setColor(typedArray.getColor(R.styleable.SegmentedProgressBar_progressBarBackgroundColor,
ContextCompat.getColor(getContext(), R.color.grey_light)));
progressBarPaint.setColor(typedArray.getColor(R.styleable.SegmentedProgressBar_progressBarColor,
ContextCompat.getColor(getContext(), R.color.progress_bar)));
dividerWidth = typedArray.getDimension(R.styleable.SegmentedProgressBar_dividerWidth, dividerWidth);
isDividerEnabled = typedArray.getBoolean(R.styleable.SegmentedProgressBar_isDividerEnabled, true);
divisions = typedArray.getInteger(R.styleable.SegmentedProgressBar_divisions, divisions);
cornerRadius = typedArray.getDimension(R.styleable.SegmentedProgressBar_cornerRadius, 2f);
} finally {
typedArray.recycle();
}
ViewTreeObserver viewTreeObserver = getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (getWidth() > 0) {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
progressBarWidth = getWidth();
dividerPositions.clear();
if (divisions > 1) {
for (int i = 1; i < divisions; i++) {
dividerPositions.add(((float) (progressBarWidth * i) / divisions));
}
}
bgRect = new RectF(0, 0, getWidth(), getHeight());
updateProgress();
}
}
});
}
}
/**
* Updates the progress bar based on manually passed percent value.
*/
private void updateProgress() {
invalidate();
}
public SegmentedProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public SegmentedProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SegmentedProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (bgRect != null) {
canvas.drawRoundRect(bgRect, cornerRadius, cornerRadius, progressBarBackgroundPaint);
for (Integer enabledDivision : enabledDivisions) {
if (enabledDivision < divisions) {
float left = 0;
if (enabledDivision != 0) {
left = dividerPositions.get(enabledDivision - 1) + dividerWidth;
}
float right = enabledDivision >= dividerPositions.size() ? progressBarWidth : dividerPositions.get(enabledDivision);
RectF rect = new RectF(left, 0, right, getHeight());
canvas.drawRoundRect(rect, cornerRadius, cornerRadius, progressBarPaint);
if (enabledDivision == 0) {
canvas.drawRect(left + cornerRadius, 0, right, getHeight(), progressBarPaint);
} else if (enabledDivision == divisions - 1) {
canvas.drawRect(left, 0, right - cornerRadius, getHeight(), progressBarPaint);
} else {
canvas.drawRect(rect, progressBarPaint);
}
}
if (divisions > 1 && isDividerEnabled) {
for (int i = 1; i < divisions; i++) {
float leftPosition = dividerPositions.get(i - 1);
canvas.drawRect(leftPosition, 0, leftPosition + dividerWidth, getHeight(), dividerPaint);
}
}
}
}
}
/**
* Set the color for the progress bar background
*
* #param color
*/
public void setBackgroundColor(int color) {
progressBarBackgroundPaint.setColor(color);
}
public void reset() {
dividerPositions.clear();
percentCompleted = 0;
updateProgress();
}
/**
* Set the color for the progress bar
*
* #param color
*/
public void setProgressBarColor(int color) {
progressBarPaint.setColor(color);
}
/**
* Set the color for the divider bar
*
* #param color
*/
public void setDividerColor(int color) {
dividerPaint.setColor(color);
}
/**
* set the width of the divider
*
* #param width
*/
public void setDividerWidth(float width) {
if (width < 0) {
Log.w(TAG, "setDividerWidth: Divider width can not be negative");
return;
}
dividerWidth = width;
}
/**
* Set whether the dividers are enabled or not.
*
* #param value true or false
*/
public void setDividerEnabled(boolean value) {
isDividerEnabled = value;
}
/**
* Sets the number of divisions in the ProgressBar.
*
* #param divisions number of divisions
*/
public void setDivisions(int divisions) {
if (divisions < 1) {
Log.w(TAG, "setDivisions: Number of Divisions cannot be less than 1");
return;
}
this.divisions = divisions;
dividerPositions.clear();
if (divisions > 1) {
for (int i = 1; i < divisions; i++) {
dividerPositions.add(((float) (progressBarWidth * i) / divisions));
}
}
updateProgress();
}
/**
* Set the enabled divisions to specified value.
*
* #param enabledDivisions number of divisions to be enabled
*/
public void setEnabledDivisions(List<Integer> enabledDivisions) {
this.enabledDivisions = enabledDivisions;
updateProgress();
}
public void setCornerRadius(float cornerRadius) {
this.cornerRadius = cornerRadius;
}
}
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SegmentedProgressBar">
<attr name="dividerColor" format="color" />
<attr name="progressBarBackgroundColor" format="color" />
<attr name="progressBarColor" format="color" />
<attr name="dividerWidth" format="dimension" />
<attr name="isDividerEnabled" format="boolean" />
<attr name="divisions" format="integer" />
<attr name="cornerRadius" format="dimension" />
</declare-styleable>
</resources>
response
I am wondering if it is possible in android studio to display text following a circular shape.
NORMAL RESULT
FINAL RESULT
layout:
<LinearLayout
android:id="#+id/layout2"
android:layout_width="260dp"
android:layout_height="250dp"
android:background="#drawable/shape"
android:textColor="#ffffff"
android:gravity="center_vertical|center_horizontal"
android:layout_alignParentRight="true"
android:layout_centerVertical="true">
<TextView
android:background="#drawable/shape"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Text"/>
</LinearLayout>
AND shape.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<corners
android:radius="130dp"
android:bottomRightRadius="0dp"
android:topRightRadius="0dp"
/>
<solid
android:color="#color/colorPrimary5"
/>
<padding
android:left="8dp"
android:top="0dp"
android:right="8dp"
android:bottom="0dp"
/>
Try this
activity_main
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
<TextView
android:id="#+id/num_txt"
android:layout_width="185dp"
android:layout_height="185dp"
android:layout_alignParentTop="true"
android:layout_marginTop="163dp"
android:background="#drawable/bg_red"
android:gravity="center"
android:text="My name is NON"
android:textColor="#FFFFFF"
android:layout_marginLeft="10dp"
android:textSize="10dp" />
<TextView
android:id="#+id/TextView02"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_alignParentRight="true"
android:layout_alignTop="#+id/TextView01"
android:layout_marginRight="90dp"
android:layout_marginTop="122dp"
android:background="#drawable/bg_red"
android:gravity="center"
android:text="My name is NON"
android:textColor="#FFFFFF"
android:textSize="10dp" />
<TextView
android:id="#+id/TextView01"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_alignTop="#+id/num_txt"
android:layout_toRightOf="#+id/num_txt"
android:background="#drawable/bg_red"
android:gravity="center"
android:text="My name is NON"
android:textColor="#FFFFFF"
android:textSize="10dp" />
</RelativeLayout>
Create a X.M.L. file in file in drawable folder named as "bg_red"
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<corners android:radius="10dip"/>
<stroke android:color="#FF0000" android:width="5dip"/>
<solid android:color="#FF0000"/>
</shape>
Output
Try the following, It may be helpful.
1) CircularTextView.class:----------
Source: https://github.com/lisawray/circletextview
public class CircleTextView extends View {
private int maxLines;
private TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
private CharSequence charSequence = "";
private int[] leftIndents;
private int[] rightIndents;
private StaticLayout layout;
public CircleTextView(Context context) {
super(context);
}
public CircleTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP) public CircleTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public int getRightIndent(int line, int width, int height) {
return getIndent(line, width, height);
}
public int getLeftIndent(int line, int width, int height) {
return getIndent(line, width, height);
}
public int getIndent(int line, int width, int height) {
int r = (int) (getSmallestDimension(width, height) / 2f);
float y = (r - line * getLineHeight());
return (int) (width / 2f - Math.sqrt((r * r) - y * y));
}
public void setTextSize(#DimenRes int dimenResId) {
textPaint.setTextSize(getPixels(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(dimenResId)));
}
int getPixels(int unit, float size) {
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
return (int) TypedValue.applyDimension(unit, size, metrics);
}
#Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
maxLines = (int) Math.floor(getSmallestDimension(w, h) / getLineHeight());
leftIndents = new int[maxLines];
rightIndents = new int[maxLines];
for (int line = 0; line < maxLines; line++) {
leftIndents[line] = getLeftIndent(line, w, h);
rightIndents[line] = getRightIndent(line, w, h);
}
makeNewLayout();
}
public void setText(CharSequence charSequence) {
this.charSequence = charSequence;
makeNewLayout();
}
private void makeNewLayout() {
StaticLayout.Builder builder = StaticLayout.Builder.obtain(charSequence, 0, charSequence.length(), textPaint, getMeasuredWidth());
builder.setIndents(leftIndents, rightIndents);
builder.setMaxLines(maxLines);
layout = builder.build();
}
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
layout.draw(canvas);
}
private int getSmallestDimension(int width, int height) {
return Math.min(width, height);
}
public float getLineHeight() {
return textPaint.getFontMetrics().bottom - textPaint.getFontMetrics().top;
}
public TextPaint getTextPaint() {
return textPaint;
}
}
2) MainActivity_.class:-----
public class MainActivity_ extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout7);
CircleTextView textView = (CircleTextView) findViewById(R.id.circle_text_view);
textView.setTextSize(R.dimen.txt_size); // declare txt_size in dimens (14sp for example).
textView.setText("This is aasdadadad nice test to insure the reliability of this shit fdgggh hfhjg khk kjghk lh lhlj hl hllh ; ;l hkjjl hlhl hl lhljh lhl hhlh hlh llh lhhj l llhl lh l lh lh");
}
}
3) layout7.xml:-------
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:background="#drawable/s"
android:layout_width="205dp"
android:layout_height="205dp"
android:id="#+id/frame"
android:layout_centerInParent="true"
android:gravity="center" />
<com.example.admin.accessories.CircleTextView
android:layout_width="150dp"
android:layout_height="150dp"
android:id="#+id/circle_text_view"
android:layout_centerInParent="true"
android:gravity="center">
</com.example.admin.accessories.CircleTextView>
</RelativeLayout>
4) s.xml:---------
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
android:innerRadius="0dp"
android:thickness="100dp"
android:useLevel="false">
<solid
android:color="#android:color/holo_red_dark"/>
</shape>
5) Output:---------
6) Note: I'm not the author of the code for the CircleTextView class. So, please click on the link above to find more detailed information about this project (bugs-enhacements...).
In my Android app I have a GridView which displays a set of images, each one in a custom subclass of ImageView (TickedImageView), which displays a tick when the image is selected.
What I want to achieve is to display a ripple when the image gets touched. I have tried setting background to
?android:attr/selectableItemBackground
with no luck, also adding a wrapper layout with this background, but nothing seems to work.
My code is as follows:
<GridView
android:id="#+id/photos_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:horizontalSpacing="2dp"
android:numColumns="#integer/photos_grid_num_columns"
android:stretchMode="columnWidth"
android:verticalSpacing="2dp"
android:layout_below="#id/spinner_toolbar" />
The layout of each GridView item is the following:
<utils.TickedImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/thumb"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/selectableItemBackground"
android:focusable="true"
android:clickable="true" />
And the ImageView subclass (TickedImageView) is the following:
package utils;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import app.R;
public class TickedImageView extends ImageView {
private boolean selected;
private Bitmap mTickBmp;
private Paint mDarkerPaint;
private View.OnClickListener onImageClickListener;
private int x, y;
public TickedImageView(Context context) {
super(context);
init();
}
public TickedImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
super.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setSelected(!isSelected());
if (onImageClickListener != null)
onImageClickListener.onClick(TickedImageView.this);
}
});
mDarkerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mDarkerPaint.setStyle(Paint.Style.FILL);
mDarkerPaint.setColor(0x80142030);
mTickBmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_done_white_48px);
}
public void setSelected(boolean selected) {
this.selected = selected;
invalidate();
}
public boolean isSelected() {
return selected;
}
#Override
protected void onDraw(#NonNull Canvas canvas) {
super.onDraw(canvas);
if (selected) {
canvas.drawRect(0, 0, canvas.getWidth(), getMeasuredWidth(), mDarkerPaint);
canvas.drawBitmap(mTickBmp, x, y, null);
}
}
#Override
public void setOnClickListener(OnClickListener listener) {
onImageClickListener = listener;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
x = (getMeasuredWidth() / 2) - (mTickBmp.getWidth() / 2);
y = (getMeasuredWidth() / 2) - (mTickBmp.getHeight() / 2);
}
}
Thank you.
To add your ripple effect, add the following :
Step 1 : Create a shape (drawable/defaultBackground.xml)
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#color/colorAccent" />
<stroke
android:width="3dp"
android:color="#color/colorAccent" />
<corners android:radius="8dp" />
Obviously you can customize it to your needs. This will be our default background.
Step 2 : Create the ripple background (drawable/rippleBackground.xml)
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/selectedRed">
<item android:drawable="#drawable/defaultBackground"/>
Once again, you can change the color to whatever you need.
Step 3 : Add the ripple to your view :
<utils.TickedImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/thumb"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/rippleBackground"
android:focusable="true"
android:clickable="true" />
Is there a way to create a ripple effect over the MapView?
My layout is presented in the end of the post.
I know about android:background="?attr/selectableItemBackground" and it works great on different kinds of Views, but not with the MapView.
What I want is the indivisible ripple effect over header_container and map_view.
To reach this I have tried putting them inside RelativeLayout and creating View with selectableItemBackground above them, but I don't like this solution because I could only make it work by specifying the exact height of that overlapping view and I want it to match the height of header and map.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:map="http://schemas.android.com/tools"
android:id="#+id/cv_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="#dimen/card_corner_radius"
card_view:cardElevation="#dimen/card_elevation"
card_view:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/header_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:orientation="vertical"
android:paddingLeft="#dimen/card_horizontal_padding"
android:paddingRight="#dimen/card_horizontal_padding">
<TextView
android:id="#+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/card_text_small_margin"
android:layout_marginTop="#dimen/card_text_big_margin"
android:text="Name"
android:textSize="#dimen/card_title_text_size" />
<TextView
android:id="#+id/tv_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/card_text_small_margin"
android:text="Address"
android:textSize="#dimen/card_subtitle_text_size" />
</LinearLayout>
<com.google.android.gms.maps.MapView
android:id="#+id/map_view"
android:layout_width="match_parent"
android:layout_height="#dimen/card_media_height"
map:liteMode="true"
map:mapType="none" />
<LinearLayout
android:id="#+id/button_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="#dimen/card_action_padding"
android:paddingTop="#dimen/card_action_padding">
<android.support.v7.widget.AppCompatButton
android:id="#+id/b_drive"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/card_action_padding"
android:layout_marginRight="#dimen/card_action_padding"
android:minHeight="0dp"
android:minWidth="0dp"
android:padding="#dimen/card_action_padding"
android:text="#string/card_action_drive"
android:textColor="#color/color_primary" />
<android.support.v7.widget.AppCompatButton
android:id="#+id/b_walk"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="0dp"
android:minWidth="0dp"
android:padding="#dimen/card_action_padding"
android:text="#string/card_action_walk"
android:textColor="#color/color_primary" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
the following class is a recipe to put any overlay on top of any view.
All you have to do is replace extends View to extends Anything and then call setOverlay(...); with the overlay (in you specific question a Ripple).
so in your case it will be:
extends MapView
and then
mapView.setOverlay(mapView.getResources().getDrawable(R.drawable.ripple));
and here is the "recipe" class
public class PressedStateView extends View {
public PressedStateView(Context context) {
super(context);
}
public PressedStateView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PressedStateView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public PressedStateView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
private Drawable overlay;
public void setOverlay(Drawable overlay) {
if (this.overlay != null) {
this.overlay.setCallback(null);
}
this.overlay = overlay;
this.overlay.setCallback(this);
this.overlay.setBounds(0, 0, getWidth(), getHeight());
invalidate();
}
#Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
this.overlay.setBounds(0, 0, w, h);
}
#Override protected boolean verifyDrawable(Drawable who) {
return super.verifyDrawable(who) || who == overlay;
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP) #Override
public void drawableHotspotChanged(float x, float y) {
super.drawableHotspotChanged(x, y);
if (overlay != null) {
overlay.setHotspot(x, y);
}
}
#Override protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (overlay != null) {
overlay.draw(canvas);
}
}
}
I have customised progressbar.
HorizontalSlider class which inherits from ProgressBar is:
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ProgressBar;
public class HorizontalSlider extends ProgressBar {
private OnProgressChangeListener listener;
private static final int padding = 2;
private static final int getMin = 11;
public interface OnProgressChangeListener {
void onProgressChanged(View v, int progress);
}
public HorizontalSlider(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, android.R.attr.progressBarStyleHorizontal);
}
public HorizontalSlider(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HorizontalSlider(Context context) {
super(context);
}
public void setOnProgressChangeListener(OnProgressChangeListener l) {
listener = l;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) {
float x_mouse = event.getX() - padding;
float width = getWidth() - 2 * padding;
int progress = Math.round((float) getMax() * (x_mouse / width));
if (progress < getMin)
progress = getMin;
if (progress > getMax())
progress = getMax();
this.setProgress(progress);
if (listener != null)
listener.onProgressChanged(this, progress);
}
return true;
}
}
UI in xml format is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="10dip"
android:paddingRight="10dip"
android:paddingTop="100dip"
android:gravity="center_horizontal" >
<com.astro.mania.classes.HorizontalSlider
android:id = "#+id/slider"
android:layout_width = "fill_parent"
android:layout_height= "wrap_content"
android:max="100"
android:layout_centerHorizontal="true"
style="?android:attr/progressBarStyleHorizontal" />
<com.astro.mania.classes.HorizontalSlider
android:id="#+id/progressBar"
android:progressDrawable="#drawable/progressbar"
android:layout_width="fill_parent"
android:layout_height="24dip"
style="?android:attr/progressBarStyleHorizontal"
android:indeterminateOnly="false"
android:max="100"
android:layout_below="#id/slider"
android:layout_marginTop="20dip" />
</RelativeLayout>
Progressbar customised as below:
<?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>
<gradient
android:startColor="#fffffe"
android:centerColor="#0b131e"
android:centerY="0.75"
android:endColor="#0d1522"
android:angle="270" />
</shape>
</item>
<item android:id="#android:id/secondaryProgress">
<clip>
<shape>
<gradient
android:startColor="#234"
android:centerColor="#234"
android:centerY="0.75"
android:endColor="#a24"
android:angle="270"
/>
</shape>
</clip>
</item>
<item android:id="#android:id/progress">
<bitmap android:src="#drawable/btn_slide_arrow" android:dither="true" />
</item>
</layer-list>
Finally the activity is like this:
public class LensaMania extends Activity {
private HorizontalSlider slider, slider2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_PROGRESS);
setContentView(R.layout.activity_lensamania);
Log.i("LensaMania", "LensaMania activity started...");
setProgressBarVisibility(true);
slider = (HorizontalSlider) this.findViewById(R.id.slider);
slider.setOnProgressChangeListener(changeListener);
slider2 = (HorizontalSlider) this.findViewById(R.id.progressBar);
slider2.setVisibility(View.VISIBLE);
slider2.setMax(100);
slider2.setProgress(11);
slider2.setOnProgressChangeListener(changeListener);
}
private OnProgressChangeListener changeListener = new OnProgressChangeListener() {
public void onProgressChanged(View v, int progress) {
setProgress(progress);
Log.i("Progress is:", "=>" + progress);
}
};
}
When I run the application and slide progreebar, the image is repeated like image below. I want to have just one image and when I slide it to left want to see just one arrow. How to ask progressbar to don't repeat the image?