I have a custom view and want to add one more custom view on that custom view. This is my custom view class:
public class CustomCircle extends View{
float radius;
Paint paint = new Paint();
String message = "";
public CustomCircle(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(getWidth()/2, getHeight()/2,radius, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
boolean isClickInCircle = false;
float x = event.getX();
float y = event.getY();
double check = Math.sqrt((x-getWidth()/2)*(x-getWidth()/2) + (y-getHeight()/2)*(y-getHeight()/2));
if (check<=radius) {
isClickInCircle= true;
}
if (isClickInCircle) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Toast.makeText(getContext(),message, Toast.LENGTH_LONG).show();
return true;
case MotionEvent.ACTION_UP:
Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
return true;
default:
break;
}
}
return false;
}
and am using another class that extends LinearLayout:
public class B extends LinearLayout {
private Paint paint;
public B(Context context) {
super(context);
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStyle(Style.FILL);
}
public void addCircle() {
CustomCircle circleBlue = new CustomCircle(getContext(), null);
circleBlue.paint.setColor(Color.WHITE);
circleBlue.paint.setAntiAlias(true);
circleBlue.radius = 160;
circleBlue.message = "Clicked";
addView(circleBlue);
CustomCircle circleRed = new CustomCircle(getContext(), null);
circleRed.paint.setColor(Color.RED);
circleRed.paint.setAntiAlias(true);
circleRed.radius = 80;
circleRed.message = "Clicked";
addView(circleRed);
}
and I'm calling the B class from the main activity class using :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
B root = new B(this);
root.addCircle();
setContentView(root);
}
The output is showing me only one circle instead of a circle inside another circle. What's wrong with my code?
And the Output is showing me only One circle instead of circle inside
circle.
You picked the wrong layout if you want to overlap children, a RelativeLayout or FrameLayout is the way to go. Also, regarding your code:
public class B extends RelativeLayout {
//...
public void addCircle() {
// the constructor that uses the AttributeSet should be added if you use the
// custom component in the xml layout
CustomCircle circleBlue = new CustomCircle(getContext());
// ...
// add it with LayoutParams
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
rlp.addRule(RelativeLayout.CENTER_IN_PARENT);
addView(circleBlue, rlp);
// the same for the other view
}
Also your two circle will have the same dimensions so they will overlap perfectly(and you'll not be able to see them), you would need to give them different dimensions, through the LayoutParams, for example:
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(200, 200);
for the first one and:
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(100, 100);
for the second one.
Is it possible that there are 2 circles in the layout but you can see only one
because it has the same color as the first circle and they are laying on top of each other?
change circleRed.paint.setColor(Color.WHITE);
to circleRed.paint.setColor(Color.BLACK);
and see what it gives
Related
I decided to try to created custom view. It is necessary to create editor with some capabilities(rotate, zoom, transform, adding overlays) on both layers(top, bottom) and make it possible to move devider to increase one layout for convenient image editing. Are there any similar works or may be someone have imagine how to start right?
I've made a custom layout that does what you asked for.
Use it programmatically, like in the example
git repository here
public class BicontLayout extends LinearLayout {
private View divider;
private View vTop, vBottom;
private LinearLayout.LayoutParams vTopParams, vBottomParams;
private int dividerClickableHeight;
public BicontLayout(Context ctx, View viewTop, View viewBottom) {
super(ctx);
this.vTop = viewTop;
this.vBottom = viewBottom;
setOrientation(LinearLayout.VERTICAL);
setWeightSum(1f);
vTopParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 0.5f);
vBottomParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 0.5f);
addView(vTop, vTopParams);
divider = new View(ctx);
divider.setBackgroundColor(Color.RED);
dividerClickableHeight = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50f, getResources().getDisplayMetrics());
addView(divider, LinearLayout.LayoutParams.MATCH_PARENT, 3);
addView(vBottom, vBottomParams);
}
private float yStartTouch;
private float yStartWeight;
private boolean isDragging;
private int[] dividerLocation = new int[2];
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if(onTouchEvent(ev)) return true;
return super.onInterceptTouchEvent(ev);
}
#Override
public boolean onTouchEvent(MotionEvent me) {
switch(me.getAction()) {
case MotionEvent.ACTION_DOWN:
yStartTouch = me.getRawY();
yStartWeight = vTopParams.weight;
divider.getLocationOnScreen(dividerLocation);
isDragging = Math.abs(dividerLocation[1]-yStartTouch) < dividerClickableHeight/2;
break;
case MotionEvent.ACTION_MOVE:
if(!isDragging) break;
float yDelta = me.getRawY() - yStartTouch;
float yDeltaProg = yDelta/BicontLayout.this.getHeight();
float yNewProg = yStartWeight + yDeltaProg;
if(yNewProg<0.1f) yNewProg=0.1f;
if(yNewProg>0.9f) yNewProg=0.9f;
vTopParams.weight = yNewProg;
vTop.setLayoutParams(vTopParams);
vBottomParams.weight = 1f - yNewProg;
vBottom.setLayoutParams(vBottomParams);
break;
case MotionEvent.ACTION_UP:
isDragging=false;
break;
}
if(isDragging) return true;
return super.onTouchEvent(me);
}
} // author Tiziano Munegato
Usage example
// vTop : top view
// vBottom : bottom view
BicontLayout doubleLayout = new BicontLayout(getContext(), vTop, vBottom);
setContentView(doubleLayout);
Happy coding!
i want to call the start method defined in Gameview class from the NewGame activity.basically i want to add onclicklistener and want to perform task specified inthe start() method whenever the button is clicked
activity:
public class NewGame extends Activity implements OnClickListener {
GameView gameview;
#Override
public void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//gameview=new GameView(this);
setContentView(R.layout.activity_new_game);
View startbutton=findViewById(R.id.start_button);
startbutton.setOnClickListener(this);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_button:
gameview.start(this);
}
}
view:
public class GameView extends View {
Path circle;
Paint cPaint;
Paint tPaint;
String z;
GameView a;
int i=65,strt,arc,leftx,topy,rightx,bottomy,maxx,maxy,minx,miny;
boolean flag1,flag2,flag3;
double n1,n2;
int n,n3=180,n4,n5=90;
float f1=180,f2=90;
int width;
int height;
Random r=new Random();
RectF oval;
public GameView(Context context,AttributeSet attrs ) {
super(context,attrs);
leftx=0;
topy=60;
rightx=150;
bottomy=120;
z= String.valueOf(Character.toChars(i));
cPaint = new Paint();
cPaint.setColor(Color.RED);
strt=45;
arc=315;
n1=Math.random()*600;
Log.d("random",z);
this.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
// cPaint.setStrokeWidth(2);
tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
tPaint.setStyle(Paint.Style.FILL_AND_STROKE);
tPaint.setColor(Color.BLACK);
float scale = getResources().getDisplayMetrics().scaledDensity;
tPaint.setTextSize(20 * scale);
}
public void start(Context context)
{
if (flag2==false)
new DrawThread(this);
}
Your gameView object is currently null. If you have it in your XML layout file, you should instantiate it in onCreate with a line like this:
gameView = (GameView) findViewById(R.id.gameView);//where gameView is the id specified in your layout file (R.layout.main, or something)
If it is not in your layout file, you need to instantiate it and add it to your layout:
gameView = new GameView(this);
gameView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
ViewGroup content = (ViewGroup) findViewById(android.R.id.content).getRootView();
content.addView(gameView);
now you will not get null pointer exceptions, and your gameview will fill the screen.
I am adding myCustomView in a linear layout multiple times, it is working fine for first instance of customView, but unable to add it multiple times.
Here is the Custom View class:
public class MultiTouchView extends View {
private float x, y;
Bitmap image;
public MultiTouchView(Context context, Bitmap image) {
super(context);
this.image = image;
// TODO Auto-generated constructor stub
}
public MultiTouchView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MultiTouchView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
canvas.drawBitmap(image, x, y, null);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getAction();
switch(action){
case MotionEvent.ACTION_MOVE:
x = event.getX();
y = event.getY();
break;
case MotionEvent.ACTION_DOWN:
x = event.getX();
y = event.getY();
break;
case MotionEvent.ACTION_UP:
break;
}
invalidate();
return true;
}
}
This is the class where i am adding custom view:
public class AndroidTouch extends Activity {
LinearLayout linear;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
linear = (LinearLayout)findViewById(R.id.linear);
Bitmap backgroundCard = BitmapFactory.decodeResource(
getResources(), R.drawable.ic_launcher);
MultiTouchView mt1 = new MultiTouchView(this, backgroundCard);
linear.addView(mt1);
Bitmap backgroundCard2 = BitmapFactory.decodeResource(
getResources(), R.drawable.icon);
MultiTouchView mt2 = new MultiTouchView(this, backgroundCard2);
linear.addView(mt2);
}
}
If you set a background color to the MultiTouchView views, then you will find that the color of the entire screen is same as the color of the 2nd view which was added.
I specified layout params for the child views and i was able to get the views to draw on screen. the modified code:
public class AndroidTouch extends Activity {
LinearLayout linear;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_c);
linear = (LinearLayout)findViewById(R.id.main);
Bitmap backgroundCard = BitmapFactory.decodeResource(getResources(), R.drawable.image1);
int w = backgroundCard.getWidth();
int h = backgroundCard.getHeight();
LayoutParams params = new LayoutParams(w, h);
MultiTouchView mt1 = new MultiTouchView(getApplicationContext(), backgroundCard);
//mt1.setBackgroundColor(Color.RED);//try uncommenting this wihtout layout params change
linear.addView(mt1, params);
Bitmap backgroundCard2 = BitmapFactory.decodeResource(getResources(), R.drawable.image2);
params = new LayoutParams(backgroundCard2.getWidth(), backgroundCard2.getHeight());
MultiTouchView mt2 = new MultiTouchView(getApplicationContext(), backgroundCard2);
//mt1.setBackgroundColor(Color.BLUE);<-- Entire screen turns blue
linear.addView(mt2, params);
}
}
But i believe you will face another problem after this. From the code it is evident that you are trying to draw the views at the touched positions. I would suggest using one single custom view and adding multiple images to the same view. Only in this case you have to determine which view needs to be drawn in a different co-ordinate and which view remains same.
Hope this helps
I have the next issue:
I have an Activity, where I want to try to add Buttons, this is my onCreate method
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
DrawView drawView = new DrawView(this);
setContentView(drawView);
context = this;
drawView.requestFocus();
}
This is the DrawView class
public class DrawView extends View implements OnTouchListener {
public static final String TAG = "DrawView";
private List<List<Point>> listaPuntos = null;
private List<Paint> listaPaints = null;
private int paintActual = 0;
public DrawView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
listaPaints = new ArrayList<Paint>();
listaPuntos = new ArrayList<List<Point>>();
this.setOnTouchListener(this);
this.setBackgroundColor(Color.WHITE);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.BLACK);
listaPaints.add(paint);
}
#Override
public void onDraw(Canvas canvas) {
for(int i=0; i<listaPaints.size(); i++){
Paint paint = listaPaints.get(i);
Point punto = null;
if(listaPuntos.size()!=0 && listaPuntos.size()>i){
List<Point> puntos = listaPuntos.get(i);
for (Point point : puntos) {
if(punto == null){
punto = point;
}
canvas.drawLine(point.x, point.y, punto.x, punto.y, paint);
punto = point;
}
}
}
}
#Override
public boolean onTouch(View view, MotionEvent event) {
if(event.getAction() != MotionEvent.ACTION_UP){
Point point = new Point();
point.x = event.getX();
point.y = event.getY();
point.paintPunto = paintActual;
if(listaPuntos.size()<=paintActual){
listaPuntos.add(new ArrayList<Point>());
}
listaPuntos.get(paintActual).add(point);
invalidate();
return true;
}else{
paintActual++;
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.BLACK);
listaPaints.add(paint);
}
return super.onTouchEvent(event);
}
Anybody knows how can I add Buttons to this Activity?? I would like to add a Button to be able to make an action and I completely canĀ“t!!
Thanks a lot for your help.
Only ViewGroup(LinearLayout,RelativeLayout) can have children.What you are doing is that you are making the DrawView as the content view of your activity which is not a container(ViewGroup) hence, you cannot add any other view(child) to it.
The solution to you problem is:
Create a xml layout file with a ViewGroup as the parent(LinearLayout, RelativeLayout,etc) containing other views or empty.
Create an instance of the DrawView.
Add this instance to the ViewGroup
Similarly create instance of other views and add them to the parent if you want to add views dynamically.
here is sample code for this:
Suppose LinearLayout with id as parent is the parent of the xml layout then:
LinearLayout parent = (LinearLayout)findViewById(R.id.parent);
//creating instance of custom view
DrawView drawView = new DrawView(this);
//adding custom view as the first child
parent.addView(drawView,0);
//adding button dynamically
Button btn = new Button(this);
btn.setText("Ok");
parent.addView(btn,1);
you should make a xml file and must use it like setContentView (R.layout.filename) and because you are trying to merge your other page contents to this xml you should include layout by now you can use this page id and can implement your any functions. So better would be if you add button in other xml and then include it in your new desired xml. this is a proper way... hope you understood what i mean. otherwise you can search in developer.android.com
You should create an XML layout file, that you will associate with your activity with the setContentView() call in onCreate().
Your layout will contain your own view, buttons, and whatever you like.
I'm trying to draw a rounded rect with a specific color, but i'm getting nothing.
I've already done lots of googling, and found some questions like this and read them all. However, none of them solved my problem. Why my onDraw method is never called?
Any help is appreciated.
public class RoundedTagItem extends RelativeLayout {
Context ctx;
String colorString;
int color;
public RoundedTagItem(Context context) {
super(context);
this.ctx = context;
color = Color.WHITE;
this.setWillNotDraw(false);
this.setPadding(10, 0, 10, 0);
}
public RoundedTagItem(Context context, String color) {
super(context);
this.ctx = context;
this.colorString = color;
this.setWillNotDraw(false);
this.setPadding(10, 0, 10, 0);
}
#Override
protected void onDraw(Canvas canvas) {
if(colorString != null)
color = Color.parseColor("#" + colorString);
int rectValue = 35;
Log.d("Rounded", "rectValue: " + rectValue);
RectF rect1 = new RectF(0, 0, rectValue, rectValue);
Paint paint = new Paint();
paint.setStrokeWidth(1);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
paint.setColor(color);
canvas.save();
canvas.drawRoundRect(rect1, 10, 10, paint);
canvas.restore();
super.onDraw(canvas);
}
public void ChangeBackgroundColor(String colorString) {
color = Color.parseColor(colorString);
invalidate();
}
}
And then I put icons on this custom view on my main class:
// add category items to view
LinearLayout categories = (LinearLayout) findViewById(R.id.detailTagImagesLayout);
for(int i = 0; i < item.getCategoryItems().size(); i++) {
RoundedTagItem v = null;
if(i == 0)
v = new RoundedTagItem(DetailActivity.this,
item.getCategoryItems().get(i).getColorCode());
else
v = new RoundedTagItem(DetailActivity.this);
ImageView img = new ImageView(DetailActivity.this);
img.setImageDrawable(Drawable.createFromPath(
item.getCategoryItems().get(i).getLightIconUrl()));
v.addView(img);
v.setTag(i);
v.setOnClickListener(new TagClickListener());
categories.addView(v);
}
Some improvements/problems you can make/fix...
You can move these lines to your constructor:
if(colorString != null)
color = Color.parseColor("#" + colorString);
Since this colorString never changes and the way you are doing it now you are calculating it every time onDraw is called (and he will be called a lot of times).
Second please move your super.onDraw(canvas) to your first line.
Third you need to define your LayoutParams on your constructor. If a View has 0 width/height its draw will never be called!
this.setLayoutParams(new LayoutParams(150, 150));
At last please make sure you are using your RoundTagItem. You can add this view to your xml using a tag like this: <your.package.RoundTagItem> where your.package is the package that you are using (com.something.blabla). If you use it like this please be sure you define the layout_width and the layout_height.
You can also add your view programmatcly by adding to your root view (you get it by using findViewById(R.layout.your_root)) or by setting your view as the main content.
RoundedTagItem myView = new RoundedTagItem(this);
setContentView(myView);
Try to create a simple single RelativeLayout XML (rounded_tag_item.xml), and inflate the custom view:
public class RoundedTagItem extends RelativeLayout {
public RoundedTagItem(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public RoundedTagItem(Context context) {
super(context);
init(context);
}
private void init(Context context) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (inflater != null) {
RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.rounded_tag_item, new RelativeLayout(context));
// rest of stuff...
}
}
}