I am building a custom EditText from this answer, this is the output I am getting,
Problem
The lines are not starting right at the top,they are starting somewhere in the middle, what could be wrong.
Here is the code,
public class LinedEditText extends EditText {
private static Paint linePaint;
static {
linePaint = new Paint();
linePaint.setColor(Color.BLACK);
linePaint.setStyle(Paint.Style.STROKE);
}
public LinedEditText(Context context, AttributeSet attributes) {
super(context, attributes);
}
#Override
protected void onDraw(Canvas canvas) {
Rect bounds = new Rect();
int firstLineY = getLineBounds(0, bounds);
int lineHeight = getLineHeight();
int totalLines = Math.max(getLineCount(), getHeight() / lineHeight);
for (int i = 0; i < totalLines; i++) {
int lineY = firstLineY + i * lineHeight;
canvas.drawLine(bounds.left, lineY, bounds.right, lineY, linePaint);
}
super.onDraw(canvas);
}
}
Here is my XML,
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/PeachPuff"
>
<TextView
android:layout_width="match_parent"
android:gravity="center"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/textView"
android:padding="8dp"
android:layout_margin="10dp"
android:background="#drawable/shape"
android:layout_gravity="center_horizontal" />
<com.random.simplenotes.LinedEditText
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
All I did was added the gravity and everything was fine,
<com.random.simplenotes.LinedEditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inputType="textMultiLine"
android:gravity="top|left"
/>
Related
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 1 year ago.
My English is not so good, but I will try..
I am having a problem with my android app (obesity measurement app).
In AVD (android virtual device), my app works well.
But, on my smartphone (Galaxy S7) my app causes an error.
Error massage is
" BMI calcu keeps stopping " .
('BMI calcu' is the name of App.)
What should I do?
Please give me a hand...
<<<< Layout file >>>>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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="comp.whcomp.whteam.bmicalcu.MainActivity"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="BMI calculator"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="4"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="#+id/textView2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="height : " />
<EditText
android:id="#+id/heightEditText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:inputType="number|numberDecimal"
android:maxLength="5" />
<TextView
android:id="#+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="cm" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="#+id/textView3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="weight : " />
<EditText
android:id="#+id/weightEditText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:inputType="number|numberDecimal"
android:maxLength="5" />
<TextView
android:id="#+id/textView4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="kg" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="#+id/textView5"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="BMI : " />
<TextView
android:id="#+id/bmiTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:inputType="textPersonName" />
<TextView
android:id="#+id/textView6"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
<comp.whcomp.whteam.bmicalcu.BmiView
android:id="#+id/BmiView2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="5" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="6"
android:orientation="horizontal"></LinearLayout>
</LinearLayout>
Main code is as following:
MainActivity.java
public class MainActivity extends Activity {
EditText mWeightEditText;
EditText mHeightEditText;
TextView mBmiTextView;
float floatWeight;
float floatHeight;
static float floatBmi = 0f;
String strBmi;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mWeightEditText = (EditText)findViewById(R.id.weightEditText);
mHeightEditText = (EditText)findViewById(R.id.heightEditText);
mBmiTextView = (TextView)findViewById(R.id.bmiTextView);
mWeightEditText.addTextChangedListener(mWatcher);
mHeightEditText.addTextChangedListener(mWatcher);
} // end of onCreate()
TextWatcher mWatcher = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence,int i,int i1,int i2){}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2){
if((mWeightEditText.getText().toString().length()>0) &&
(mHeightEditText.getText().toString().length()>0)) {
if(mHeightEditText.getText().toString().equals("0")){
} else {
floatWeight=Float.parseFloat(mWeightEditText.getText().toString());
floatHeight=Float.parseFloat(mHeightEditText.getText().toString());
floatBmi=(floatWeight/(floatHeight/100f)) / (floatHeight/100f);
strBmi = String.format("%.1f", floatBmi);
mBmiTextView.setText(strBmi);
}
} else {
mBmiTextView.setText("");
floatBmi = 0f;
}
} // end of onTextchange()
#Override
public void afterTextChanged(Editable editable) {}
}; // end of TextWatcher
}
BmiView.java
public class BmiView extends SurfaceView implements SurfaceHolder.Callback {
Context mContext;
private BmiThread mThread;
int screenWidth;
int screenHeight;
int radius;
int xOfCenterOfCircle;
int yOfCenterOfCircle;
int tOfRectOfArc;
int bOfRectOfArc;
int lOfRectOfArc;
int rOfRectOfArc;
int xOfNeedleEnd = 0;
int yOfNeedleEnd = 0;
int intBmi;
RectF rect;
private Paint mPaintGreen;
private Paint mPaintBlack;
private Paint mPaintNeedle;
// constructor
public BmiView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
mContext = context;
mPaintGreen = new Paint();
mPaintBlack = new Paint();
mPaintNeedle = new Paint();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
screenWidth = w;
screenHeight = h;
if ( h > w/2 ) {
radius = w*4/10;
} else {
radius = h*4/5;
}
xOfCenterOfCircle = w/2;
yOfCenterOfCircle = h*4/5;
tOfRectOfArc = yOfCenterOfCircle - radius;
bOfRectOfArc = yOfCenterOfCircle + radius;
lOfRectOfArc = xOfCenterOfCircle - radius;
rOfRectOfArc = xOfCenterOfCircle + radius;
mPaintGreen.setColor(Color.GREEN);
mPaintBlack.setColor(Color.BLACK);
mPaintNeedle.setColor(Color.RED);
mPaintNeedle.setStrokeWidth(10);
rect = new RectF();
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
mThread = new BmiThread(surfaceHolder);
mThread.setRunning(true);
mThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder,int i,int i1,int i2){}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
boolean retry = true;
mThread.setRunning(false); // terminate mThread
while (retry) {
try {
mThread.join(); // wait for mThread to finish
retry = false;
}
catch (InterruptedException e) {}
}
}
class BmiThread extends Thread {
private SurfaceHolder surfaceHolder;
private boolean threadIsRunning = true; // running by default
public BmiThread(SurfaceHolder holder) {
surfaceHolder = holder;
}
public void setRunning (boolean running) {
threadIsRunning = running;
}
public void run() {
Canvas canvas = null;
while (threadIsRunning) {
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
canvas.drawColor(Color.WHITE);
rect.set(lOfRectOfArc, tOfRectOfArc, rOfRectOfArc, bOfRectOfArc);
canvas.drawArc(rect, 180, 180, false, mPaintGreen);
intBmi = (int)MainActivity.floatBmi;
if(intBmi > 40) {
intBmi = 40;
}
double deg = 180*(intBmi/40d), rad;
rad = Math.toRadians(deg);
xOfNeedleEnd = xOfCenterOfCircle - (int)(( Math.cos(rad) )*radius);
yOfNeedleEnd = yOfCenterOfCircle - (int)(( Math.sin(rad) )*radius);
canvas.drawLine(xOfCenterOfCircle, yOfCenterOfCircle, xOfNeedleEnd,
yOfNeedleEnd, mPaintNeedle);
canvas.drawCircle(xOfCenterOfCircle, yOfCenterOfCircle, 10,
mPaintBlack);
}
} finally {
if (canvas != null)
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end of while()
} // end of run()
} // end of thread.
}
<<<< Logcat message >>>>
08-02 16:00:18.127 3086-3213/comp.whcomp.whteam.bmicalcu E/AndroidRuntime: FATAL EXCEPTION: Thread-7
Process: comp.whcomp.whteam.bmicalcu, PID: 3086
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int)' on a null object reference
at comp.whcomp.whteam.bmicalcu.BmiView$BmiThread.run(BmiView.java:123)
Check that you are creating an instance before trying to set the colour. It is complaining because the object you're trying to set the colour for doesn't exist at the time you're trying to set it.
Hmm. For the first glance, your code seems correct. Maybe is because your BmiView has a height of 0dp? - see the layout
I am trying to create a simple ball and stick game in android and have the following xml file for android.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
tools:context=".BallActivity">
<learn.com.application.BallView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/ball"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Left"
android:onClick="moveleft"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Right"
android:onClick="moveright"/>
</LinearLayout>
</LinearLayout>
The LinearLayout containing the buttons is not visible as the BallView is match_parent. But if i declare height of BallView as wrap_content It does not work. How can i show the left and right buttons on the bottom. What else can i use for moving the stick left or right.
Code for BallView
public class BallView extends android.support.v7.widget.AppCompatImageView {
private Context mContext;
int x = -1;
int y = -1;
boolean first=true;
private int xVelocity = 10;
private int yVelocity = 5;
private Handler h;
public static int FRAME_RATE = 50;
public static int stickx=0,sticky=0;
public static int width=0;
public static int height=0;
boolean gameover=false;
public BallView(Context context,AttributeSet s) {
super(context,s);
mContext=context;
h=new Handler();
}
private Runnable r=new Runnable() {
#Override
public void run() {
invalidate();
}
};
#Override
protected void onDraw(Canvas canvas) {
if(first) {
stickx = getWidth() / 2 - 40;
sticky = getHeight() - 60;
width = getWidth();
height = getHeight();
first=false;
}
Bitmap bmp= BitmapFactory.decodeResource(mContext.getResources(),R.drawable.ball1);
if(x<0 && y<0)
{
x=getWidth()/2;
y=getHeight()/2;
}
else {
x += xVelocity;
y += yVelocity;
if (x + bmp.getWidth() > getWidth() || (x < 0))
xVelocity = xVelocity * -1;
if (y < 0)
yVelocity = yVelocity * -1;
if (y + bmp.getHeight() >= sticky) {
if (x + bmp.getWidth() > stickx && x + bmp.getWidth() < (stickx + 180)) {
yVelocity = yVelocity * -1;
Log.v("ball","collision");
}
else {
Log.v("ball", "game over");
gameover=true;
}
}
}
RectF rr=new RectF();
int right=stickx+180;
int bottom=sticky+30;
rr.set(stickx,sticky,right,bottom);
Paint p=new Paint();
canvas.drawRoundRect(rr,5,5,p);
canvas.drawBitmap(bmp,x,y,null);
if(!gameover)
h.postDelayed(r,FRAME_RATE);
}
}
<?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=".BallActivity">
<learn.com.application.BallView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/tablerow"
android:id="#+id/ball"/>
<TableRow
android:id="#+id/tablerow"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Left"
android:onClick="moveleft"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Right"
android:onClick="moveright"/>
</TableRow>
</RelativeLayout>
Instead of using LinearLayout, I would prefer to use RelativeLayout and TableRow as shown
This will be my first question, so I apologize for my probable mistakes.
I'm trying to add a red circle each time I press the button I've incorported to my layout. I'd like all circles stayed in the layout:
<?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:id="#+id/panelJuego"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.76"
android:orientation="horizontal" >
</LinearLayout>
<Button
android:id="#+id/button1"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="botonRojo"
android:text="Button" />
</LinearLayout>
The java code related with my trying is:
public void botonRojo(View v) {
LinearLayout panelJuego = (LinearLayout) findViewById(R.id.panelJuego);
PonCirculo circulo = new PonCirculo(this, 30, 30, "#FF0000");
circulo.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
panelJuego.addView(circulo);
}
public class PonCirculo extends View {
private int radio = 30;
private String color;
public PonCirculo(Context context, int x, int y, String color) {
super(context);
Cx = Cx + x;
Cy = Cy + y;
this.color = color;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.parseColor(color));
canvas.drawCircle(Cx, Cy, radio, paint);
}
Actually each time I press the button a red filled circle appears in the android screen but when I press the button again a new circle appears and the fomer disappears. Can anyone help me? Thanks.
I'm assuming you are just trying to add each circle under each other when the button is pressed.
Currently you are adding a new view each time now but it is over-laying the previous view. You need add the views giving each new circle a unique id. Then place the new circle underneath or whatever position you choose. I'm giving you some example code that I changed to use a relative layout and I place each circle under the previous one. This should get you started with what you are looking for:
Example Layout:
<?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:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/relativeCircleLayout">
</RelativeLayout>
<Button
android:id="#+id/button1"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add Circle"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:onClick="botonRojo"/>
</RelativeLayout>
Example Code:
public class MainActivity extends AppCompatActivity {
ArrayList<PonCirculo> viewList = new ArrayList<PonCirculo>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void botonRojo(View v) {
RelativeLayout panelJuego = (RelativeLayout) findViewById(R.id.relativeCircleLayout);
PonCirculo circulo = new PonCirculo(this, 30, 30, "#FF0000");
circulo.setId(View.generateViewId());
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 100);
if(!viewList.isEmpty()) {
int id = viewList.get(viewList.size()-1).getId();
params.addRule(RelativeLayout.BELOW, id);
}
panelJuego.addView(circulo, params);
viewList.add(circulo);
}
public class PonCirculo extends View {
private int radio = 30;
private String color;
int Cx, Cy;
public PonCirculo(Context context, int x, int y, String color) {
super(context);
Cx = Cx + x;
Cy = Cy + y;
this.color = color;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.parseColor(color));
canvas.drawCircle(Cx, Cy, radio, paint);
}
}
}
I have to do this layout:
I was trying to align the views, using RelativeLayout and layout_toRightOf, layout_below, etc, but the best that I achieved was this:
Here are the xml:
<?xml version="1.0" encoding="utf-8"?>
<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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<RelativeLayout
android:id="#+id/big"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="#drawable/circular"
android:layout_margin="10dp"
android:layout_centerInParent="true"/>
<RelativeLayout
android:id="#+id/right"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/circular"
android:layout_toRightOf="#+id/big"
android:layout_centerVertical="true"/>
<RelativeLayout
android:id="#+id/left"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/circular"
android:layout_toLeftOf="#+id/big"
android:layout_centerVertical="true"/>
<RelativeLayout
android:id="#+id/top"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/circular"
android:layout_above="#+id/big"
android:layout_centerHorizontal="true"/>
<RelativeLayout
android:id="#+id/bottom"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/circular"
android:layout_below="#+id/big"
android:layout_centerHorizontal="true"/>
<RelativeLayout
android:id="#+id/northeast"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/circular"
android:layout_toRightOf="#+id/big"
android:layout_alignTop="#+id/top"/>
<RelativeLayout
android:id="#+id/northwest"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/circular"
android:layout_toLeftOf="#+id/big"
android:layout_alignTop="#+id/top"/>
<RelativeLayout
android:id="#+id/southeast"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/circular"
android:layout_toRightOf="#+id/big"
android:layout_below="#+id/big"/>
<RelativeLayout
android:id="#+id/southwest"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/circular"
android:layout_toLeftOf="#+id/big"
android:layout_below="#+id/big"/>
</RelativeLayout>
I'm trying to avoid using margin on the little circles, because the diagonal circles have to be aligned exactly to the center, in comparison with the top/bottom/right/left circles.
How can I do that?
I show you another approach.
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class CircleMenu extends View {
private Paint mainPaint;
private Paint secondPaint;
private Paint textPaint;
private int radius_main =130;
private int menuRadialButtonsCount =7;
private int menuInnerPadding = 40;
private int radialCircleRadius = 60;
private int textPadding = 25;
private double startAngle = - Math.PI/2f;;
public CircleMenu(Context context) {
super(context);
}
public CircleMenu(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
mainPaint = new Paint();
mainPaint.setColor(Color.BLUE);
secondPaint = new Paint();
secondPaint.setColor(Color.DKGRAY);
textPaint = new Paint();
textPaint.setColor(Color.BLACK);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int centerX = canvas.getWidth()/2 ;
int centerY= canvas.getHeight()/2;
canvas.drawCircle(centerX,centerY,radius_main,mainPaint);
for(int i=0;i<menuRadialButtonsCount;i++){
double angle =0;
if(i==0){
angle = startAngle;
}else{
angle = startAngle+(i * ((2 * Math.PI) / menuRadialButtonsCount));
}
int x = (int) (centerX + Math.cos(angle)*(radius_main+menuInnerPadding+radialCircleRadius));
int y = (int) (centerY + Math.sin(angle)*(radius_main+menuInnerPadding+radialCircleRadius));
canvas.drawCircle(x,y,radialCircleRadius,secondPaint);
float tW = textPaint.measureText("Text "+i);
canvas.drawText("Text "+i,x-tW/2,y+radialCircleRadius+textPadding,textPaint);
}
}
}
You can extend this class, add methods to set dimmensions from resources, controlling numer of circles, their size, paddings, onTouch, shadows, colors ....
<your.package.CircleMenu
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Updated version:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
public class CircleMenu extends View {
public static interface IMenuListener{
public void onMenuClick(MenuCircle item);
}
public static class MenuCircle{
private int x,y,radius;
public int id;
public String text;
}
private Paint mainPaint;
private Paint secondPaint;
private Paint textPaint;
private int radius_main =130;
private int menuInnerPadding = 40;
private int radialCircleRadius = 60;
private int textPadding = 25;
private double startAngle = - Math.PI/2f;
private ArrayList<MenuCircle> elements;
private IMenuListener listener;
public void setListener(IMenuListener listener){
this.listener = listener;
}
public void clear(){
elements.clear();
listener=null;
}
public CircleMenu(Context context) {
super(context);
init();
}
public CircleMenu(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
elements = new ArrayList<>();
}
public void addMenuItem(String text,int id){
MenuCircle item = new MenuCircle();
item.id = id;
item.text=text;
elements.add(item);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
mainPaint = new Paint();
mainPaint.setColor(Color.BLUE);
secondPaint = new Paint();
secondPaint.setColor(Color.DKGRAY);
textPaint = new Paint();
textPaint.setColor(Color.BLACK);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int centerX = canvas.getWidth()/2 ;
int centerY= canvas.getHeight()/2;
canvas.drawCircle(centerX,centerY,radius_main,mainPaint);
for(int i=0;i<elements.size();i++){
double angle =0;
if(i==0){
angle = startAngle;
}else{
angle = startAngle+(i * ((2 * Math.PI) / elements.size()));
}
elements.get(i).x = (int) (centerX + Math.cos(angle)*(radius_main+menuInnerPadding+radialCircleRadius));
elements.get(i).y = (int) (centerY + Math.sin(angle)*(radius_main+menuInnerPadding+radialCircleRadius));
canvas.drawCircle( elements.get(i).x,elements.get(i).y,radialCircleRadius,secondPaint);
float tW = textPaint.measureText(elements.get(i).text);
canvas.drawText(elements.get(i).text,elements.get(i).x-tW/2,elements.get(i).y+radialCircleRadius+textPadding,textPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN){
for(MenuCircle mc : elements){
double distance = Math.hypot(event.getX()-mc.x,event.getY()-mc.y);
if(distance<= radialCircleRadius){
//touched
if(listener!=null)
listener.onMenuClick(mc);
return true;
}
}
}
return super.onTouchEvent(event);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
}
In Fragment:
CircleMenu cm = (CircleMenu) view.findViewById(R.id.c_menu);
cm.addMenuItem("one",1);
cm.addMenuItem("two",2);
cm.addMenuItem("three",3);
cm.addMenuItem("ten",10);
cm.addMenuItem("oh oh",156);
cm.addMenuItem("exit",134);
cm.setListener(new CircleMenu.IMenuListener() {
#Override
public void onMenuClick(CircleMenu.MenuCircle item) {
Toast.makeText(getActivity(),item.text+" "+item.id,Toast.LENGTH_LONG).show();
}
});
This helps you.
<?xml version="1.0" encoding="utf-8"?>
<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">
<RelativeLayout
android:id="#+id/rlBig"
android:layout_width="250dp"
android:layout_height="260dp"
android:layout_centerInParent="true">
<RelativeLayout
android:id="#+id/big"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_centerInParent="true"
android:background="#drawable/round_orange_schdule_meet" />
<RelativeLayout
android:id="#+id/northwest"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="10dp"
android:background="#drawable/round_orange_schdule_meet" />
<RelativeLayout
android:id="#+id/southeast"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="#drawable/round_orange_schdule_meet" />
<RelativeLayout
android:id="#+id/southwest"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:background="#drawable/round_orange_schdule_meet" />
<RelativeLayout
android:id="#+id/northeast"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="#drawable/round_orange_schdule_meet" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/right"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/rlBig"
android:layout_marginLeft="-15dp"
android:background="#drawable/round_orange_schdule_meet" />
<RelativeLayout
android:id="#+id/left"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginRight="-15dp"
android:layout_toLeftOf="#+id/rlBig"
android:background="#drawable/round_orange_schdule_meet" />
<RelativeLayout
android:id="#+id/top"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_above="#+id/rlBig"
android:layout_marginBottom="-15dp"
android:layout_centerHorizontal="true"
android:background="#drawable/round_orange_schdule_meet" />
<RelativeLayout
android:id="#+id/bottom"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_below="#+id/rlBig"
android:layout_centerHorizontal="true"
android:layout_marginTop="-10dp"
android:background="#drawable/round_orange_schdule_meet" />
Output is:
You should go with a custom-view here - with a lot of force you might be able to do it with a layout - but it will be messy and not perform well
historically i have stupid problems with layouts, and now i try to fill this blank in my brain. Watch this example, i try to do some axis for graphic, and i want to pack them like this:
Vertical line by left side
Horizontal line by bottom
Spacer between Vert & Horiz in left bottom corner
Other place fill by graph
(Sorry not allowed to post images.I hope you see graphics axis before, no need to explain.)
And this what i got at now:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.example.graphicformatting.Axis
android:id="#+id/yaxis"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginBottom="40dp"
android:background="#color/backpanel_dark"
custom:ishorizontal="false" />
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textMultiLine"
android:text="This text field mean my own graphic widget, which not have any OnMeasured function or any specific and it's painting with size, which assigment by parent/ Just use getHeight and getWeight" >
<requestFocus />
</EditText>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<View
android:layout_width="40dp"
android:layout_height="40dp"
android:background="#color/backpanel_dark" />
<com.example.graphicformatting.Axis
android:id="#+id/yaxis"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="40dp"
android:background="#color/backpanel_dark"
custom:ishorizontal="true" />
</LinearLayout>
And this is code of my axises:
package com.example.graphicformatting;
public class Axis extends View {
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
public static final int DP_SIZE = 40;
int type = -1;
int size;
Paint painter;
public Axis(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.com_example_graphicformatting_Axis);
final int N = a.getIndexCount();
for (int i = 0; i < N; ++i) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.com_example_graphicformatting_Axis_ishorizontal:
if (a.getBoolean(attr, true)) {
type = HORIZONTAL;
} else
type = VERTICAL;
break;
default:
Log.d("axis", "Found unexpected state");
}
}
a.recycle();
final float scale = getContext().getResources().getDisplayMetrics().density;
size = (int) (DP_SIZE * scale + 0.5f);
painter = new Paint();
painter.setColor(Color.RED);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
if (type == HORIZONTAL) {
this.setMeasuredDimension(parentWidth, size);
this.setLayoutParams(new LinearLayout.LayoutParams(parentWidth, size));
// Log.d("axis", "Size of horizontal calc: " + (parentWidth) + " "
// + size);
} else if (type == VERTICAL) {
this.setMeasuredDimension(size, parentHeight);
this.setLayoutParams(new LinearLayout.LayoutParams(size, parentHeight));
// Log.d("axis", "Size of vertical calc: " + size + " "
// + (parentHeight));
} else { // Для нормального отображения в конструкторе
this.setMeasuredDimension(size, size);
this.setLayoutParams(new LinearLayout.LayoutParams(size, size));
}
}
#Override
protected void onDraw(Canvas canvas) {
if (type == VERTICAL) {
canvas.drawRect(0, 0, size, getHeight(), painter);
} else {
canvas.drawRect(0, getHeight() - size, getWidth(), getHeight(), painter);
}
super.onDraw(canvas);
}
}
How to custom my Layouts to get right pic?
Ou, this using for set horizontal/vertical attribute (value/attrs.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="com.example.graphicformatting.Axis">
<attr name="ishorizontal" format="boolean"></attr>
</declare-styleable>
</resources>