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" />
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 want to put Circle class into my layout. I tried it but app got stopped on creating. I think the problem is in xml code in the first line which is under. Kindly guide me.
<com.package.Circle
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/circle"
android:layout_width="300dp"
android:layout_height="300dp" />
XML file:
<?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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.example.zohaib.animatedcircle.MainActivity"
tools:showIn="#layout/activity_main">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<com.package.Circle
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/circle"
android:layout_width="300dp"
android:layout_height="300dp" />
</RelativeLayout>
Circle.java
package com.example.zohaib.animatedcircle;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class Circle extends View {
private static final int START_ANGLE_POINT = 90;
private final Paint paint;
private final RectF rect;
private float angle;
public Circle(Context context, AttributeSet attrs) {
super(context, attrs);
final int strokeWidth = 40;
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(strokeWidth);
//Circle color
paint.setColor(Color.RED);
//size 200x200 example
rect = new RectF(strokeWidth, strokeWidth, 200 + strokeWidth, 200 + strokeWidth);
//Initial Angle (optional, it can be zero)
angle = 120;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint);
}
public float getAngle() {
return angle;
}
public void setAngle(float angle) {
this.angle = angle;
}
}
MainActivity.java
package com.example.zohaib.animatedcircle;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Circle circle = (Circle) findViewById(R.id.circle);
CircleAngleAnimation animation = new CircleAngleAnimation(circle, 240);
animation.setDuration(1000);
circle.startAnimation(animation);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
The XML element name needs to be the fully qualified class name of your custom View class. In this case, it would be com.example.zohaib.animatedcircle.Circle, instead of com.package.Circle.
<com.example.zohaib.animatedcircle.Circle
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/circle"
android:layout_width="300dp"
android:layout_height="300dp" />
I am following this tutorial: http://danielnadeau.blogspot.ca/2012/01/android-canvas-beginners-tutorial.html
When I look at things in the "Graphical Layout" tab in Eclipse, I see the expected result (a red square in the center of the display), but when I actually run the app, I just get a large black rectangle, and I can't seem to figure out why. I've searched some posts, but have not found an answer that seems to apply to my situation.
MainActivity.java
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
activity_mail.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.hintonworks.cantstop.CustomView
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="#+id/my_view" />
</RelativeLayout>
CustomView.java
package com.hintonworks.cantstop;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class CustomView extends SurfaceView implements SurfaceHolder.Callback {
public CustomView (Context context) {
super(context);
}
public CustomView (Context context, AttributeSet attrs) {
super(context);
}
#Override
public void onDraw (Canvas canvas) {
int dCenter = 40; //Distance from center in px, NOT in dp
int centerX = (int)(getWidth()/2);
int centerY = (int)(getHeight()/2);
Paint paint = new Paint();
paint.setColor(Color.RED); //The square will draw in the color blue now
Rect rect = new Rect(centerX-dCenter, centerY-dCenter, centerX+dCenter, centerY+dCenter);
canvas.drawRect(rect, paint);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
#Override
public void surfaceCreated(SurfaceHolder holder) {
setWillNotDraw(false); //Allows us to use invalidate() to call onDraw()
postInvalidate();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {}
}
Thanks for any insight. This is my stab at using the canvas, until now I have been using drawable resources.
I have created a simple demo application in android for drawing ,now can any one say me how can i remove view and clear screen in just one click .I have tried as below:please help me to do it....thanx in advance..!
main.java
package com.example.singletouch;
import com.example.singletouch.R.attr;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class MainActivity extends Activity {
ImageView pen;
SingleTouchView mDrawView;
ImageView remove;
LinearLayout pens;
LinearLayout pen1, pen2, pen3, pen4;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDrawView = (SingleTouchView) findViewById(R.id.myview);
pen = (ImageView) findViewById(R.id.pen);
pens = (LinearLayout) findViewById(R.id.linear);
pens.setVisibility(View.GONE);
pen1 = (LinearLayout) findViewById(R.id.pen1);
pen2 = (LinearLayout) findViewById(R.id.pen2);
pen3 = (LinearLayout) findViewById(R.id.pen3);
pen4 = (LinearLayout) findViewById(R.id.pen4);
remove=(ImageView)findViewById(R.id.remove);
/*
* pen1.setOnClickListener(this); pen2.setOnClickListener(this);
* pen3.setOnClickListener(this); pen4.setOnClickListener(this);
*/
pen.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
pens.setVisibility(View.VISIBLE);
}
});pens.setVisibility(View.GONE);
pen1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mDrawView.setPen(SingleTouchView.DrawingPens.PEN_1);
pens.setVisibility(View.GONE);
}
});
pen2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mDrawView.setPen(SingleTouchView.DrawingPens.PEN_2);
pens.setVisibility(View.GONE);
}
});
pen3.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
pens.setVisibility(View.GONE);
mDrawView.setPen(SingleTouchView.DrawingPens.PEN_3);
}
});
pen4.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
pens.setVisibility(View.GONE);
mDrawView.setPen(SingleTouchView.DrawingPens.PEN_4);
}
});
remove.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
}
SingleTouchView.java
package com.example.singletouch;
import java.util.AbstractMap;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import android.R.color;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.Switch;
public class SingleTouchView extends View{
public int width;
public int height;
public Bitmap mBitmap;
public Canvas mCanvas;
public Path mPath;
public Paint mBitmapPaint;
Context context;
public Paint circlePaint;
public Path circlePath;
public enum DrawingPens {
PEN_1(6),
PEN_2(4),
PEN_3(2),
PEN_4(1);
final public Paint mPaint;
/**
* Constructor
*
* #param width width of stroke
* #param color color of stroke
*/
private DrawingPens(final int width) {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(width);
//mPaint.setColor(color);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
}
/**
* #return corresponding paint
*/
Paint getPaint() {
return mPaint;
}
}
public SingleTouchView(final Context context) {
super(context);
init(context);
}
public SingleTouchView(final Context context, final AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SingleTouchView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
init(context);
}
/** To store Paint - Path relation */
// TODO: depending on exact limits, more optimal ways can be found
private ConcurrentLinkedQueue<Map.Entry<Path, DrawingPens>> mPaths = new ConcurrentLinkedQueue<Map.Entry<Path, DrawingPens>>();
/** Cached current path, <b>NOTE:</b> this field is tail at mPaths and is used it only for caching, not drawing */
private Path mCurrentPath;
/**
* Inits internal views data, should be called from every constructor
*
* #param context {#link Context}
*/
private void init(final Context context) {
/* TODO: if some values of paints cannot be determined in static context (in enum),
then Paints should be created here and used via EnumMap */
// Initial pen
setPen(DrawingPens.PEN_1);
}
#Override
public void onDraw(Canvas canvas){
// just to draw background
super.onDraw(canvas);
// Draw all paths
for (Map.Entry<Path, DrawingPens> entry : mPaths) {
canvas.drawPath(entry.getKey(), entry.getValue().getPaint());
}
}
#Override
public boolean onTouchEvent(MotionEvent me){
float eventX = me.getX();
float eventY = me.getY();
switch (me.getAction()) {
case MotionEvent.ACTION_DOWN:
mCurrentPath.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
mCurrentPath.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
break;
}
invalidate();
return true;
}
/**
* Setter for new pen
*
* #param pen {#link DrawingPens} to be used for next drawing
*/
public void setPen(final DrawingPens pen) {
// put latest item to the queue
mCurrentPath = new Path();
mPaths.add(new AbstractMap.SimpleImmutableEntry<Path, DrawingPens>(mCurrentPath, pen));
}
public void clear(View v){
}
}
main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".MainActivity" >
<com.example.singletouch.SingleTouchView
android:id="#+id/myview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/pen" />
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#drawable/menubar"
android:padding="2dp"
android:weightSum="4" >
<ImageView
android:id="#+id/pen"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_weight="1"
android:gravity="center"
android:src="#drawable/pen" />
<ImageView
android:id="#+id/eraser"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_weight="1"
android:src="#drawable/eraser" />
<ImageView
android:id="#+id/color"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_weight="1"
android:src="#drawable/color" />
<ImageView
android:id="#+id/remove"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_weight="1"
android:src="#drawable/remove" />
</LinearLayout>
<LinearLayout
android:id="#+id/linear"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/linearLayout1"
android:layout_alignParentLeft="true"
android:background="#eeeeee"
android:orientation="horizontal"
android:visibility="gone"
android:weightSum="4" >
<LinearLayout
android:id="#+id/pen1"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center" >
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="#drawable/pen1" />
</LinearLayout>
<LinearLayout
android:id="#+id/pen2"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="#drawable/pen2" />
</LinearLayout>
<LinearLayout
android:id="#+id/pen3"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="#drawable/pen3" />
</LinearLayout>
<LinearLayout
android:id="#+id/pen4"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="#drawable/pen4" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
Jus use ...
mCanvas.drawColor(Color.BLACK);
... for clearing the canvas or any other color you want to have in background. E.g.
remove.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// clear canvas contents
mCanvas.drawColor(Color.BLACK);
// create new path list; old one will be garbage collected
ConcurrentLinkedQueue<Map.Entry<Path, DrawingPens>> mPaths =
new ConcurrentLinkedQueue<Map.Entry<Path, DrawingPens>>();
pens.setVisibility(View.VISIBLE);
}
p.s.: for removing a view dynamically from its container use removeView(....), e.g.
((ViewGroup)viewToRemove.getParent()).removeView(viewToRemove);
Hope this helps ... Cheers!
remove.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
layout.removeView(mDrawView);
mDrawView = new SingleTouchView(MainActivity.this);
layout.addView(mDrawView);
}
});
Put the portion of the screen you want cleared in a single layout in xml eg
<RelativeLayout
android:id="#+id/layout"
android:layout_width="wrap_content"
android:layout_height= "wrap_content">
The Views that have to be gone on click
</RelativeLayout>
Then in your code in onClick() of the button give
((RelativeLayout) findViewById(R.id.layout)).setVisiblity(View.GONE));
EDIT :
If you want the ImageView cleared use :
((ImageView) findViewById(R.id.imageView)).setImageDrawable(null);
instead of drawing solid color you can draw transparent color this help you don't cover the other views if you use them as a background for the canvas
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
I got this from this answer: https://stackoverflow.com/a/10882301/8113211
I am trying to develop a simple map application, which will display a map in the screen.
When the user moves the cursor on screen, I want to display 2 perpendicular lines over my map. I had tried many examples to get an idea for that, but unfortunately, didn't succeed.
How can I make this?
And as one previous questionhere I had tried. but didn't get the answer. Can anyone guide me?
My main.xml is as following:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView android:id="#+id/main_imagemap"
android:src="#drawable/worldmap"
android:clickable="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
And my activity file(i had just started it..)
import android.app.Activity;
import android.os.Bundle;
import android.widget.ImageView;
public class LineMapActivity extends Activity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView map_image = (ImageView)findViewById(R.id.main_imagemap);
}
}
And as in that link, i had also added MyImageView.
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.widget.ImageView;
public class MyImageView extends ImageView
{
public MyImageView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
canvas.drawLine(0, 0, 20, 20, p);
super.onDraw(canvas);
}
}
Now how can i add this MyImageView to my app?
Finally I figured out a solution. It's a simple program which draws a line over an Image.
Here is my main.xml file (com.ImageDraw.MyImageView is my custom view, code below):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.ImageDraw.MyImageView android:id="#+id/main_imagemap"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
And here is the main activity:
import android.app.Activity;
import android.os.Bundle;
public class MyActivity extends Activity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
and this is my custom image view (MyImageView):
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MyImageView extends SurfaceView implements SurfaceHolder.Callback
{
private CanvasThread canvasthread;
public MyImageView(Context context) {
super(context);
getHolder().addCallback(this);
canvasthread = new CanvasThread(getHolder(), this);
setFocusable(true);
}
public MyImageView(Context context, AttributeSet attrs)
{
super(context,attrs);
getHolder().addCallback(this);
canvasthread = new CanvasThread(getHolder(), this);
setFocusable(true);
}
protected void onDraw(Canvas canvas) {
Log.d("ondraw", "ondraw");
Paint p = new Paint();
Bitmap mapImg = BitmapFactory.decodeResource(getResources(), R.drawable.mybitmap);
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(mapImg, 0, 0, null);
p.setColor(Color.RED);
canvas.drawLine(0, 0, 100, 100, p);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
canvasthread.setRunning(true);
canvasthread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
canvasthread.setRunning(false);
while (retry)
{
try
{
canvasthread.join();
retry = false;
}
catch (InterruptedException e) {
// TODO: handle exception
}
}
}
}
And finally here is my CanvasThread:
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class CanvasThread extends Thread
{
private SurfaceHolder surfaceHolder;
private MyImageView myImageView;
private boolean run = false;
public CanvasThread(SurfaceHolder s, MyImageView m)
{
surfaceHolder = s;
myImageView = m;
}
public void setRunning(boolean r)
{
run = r;
}
public void run()
{
Canvas c;
while(run)
{
c=null;
try
{
c= surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
myImageView.onDraw(c);
}
}
finally
{
if(c!=null)
{
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
You can find more details in this tutorial
Error you are getting because you are trying to casting ImageView object to MyImageView object.
Just fix the xml to include your object instead of an imageview like so (note that com.your.package.MyImageView should be the full package name of the package containing your class and then the class name)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.your.package.MyImageView android:id="#+id/main_imagemap"
android:src="#drawable/worldmap"
android:clickable="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>