I'm trying to implement a subclass of TextView that prints the text vertically rotated, but I'm having troubles printing the text in the color I specify from an XML layout. The class code is:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.widget.TextView;
public class VerticalTextView extends TextView {
private Rect bounds = new Rect();
private TextPaint textPaint;
public VerticalTextView(Context context) {
super(context);
}
public VerticalTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
textPaint = getPaint();
textPaint.getTextBounds((String) getText(), 0, getText().length(), bounds);
setMeasuredDimension((int) (bounds.height() + textPaint.descent()), bounds.width());
}
#Override
protected void onDraw(Canvas canvas) {
canvas.rotate(-90, bounds.width(), 0);
canvas.drawText((String) getText(), 0, -bounds.width() + bounds.height(), textPaint);
}
}
I have no need of custom properties for this view, so I'm not declaring a styleable for it.
I'm using this view in my activity by this layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.verticaltextview.VerticalTextView
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Hello World" android:textColor="#ff0000ff"
android:textStyle="italic" />
</LinearLayout>
As you can see, I'm specifying both the text color (blue) and the text style (italic), but only the style is applied, as the text is printed in black. If in the onDraw() method I hardcode a color by doing textPaint.setColor(0xff00ff00), then the text is correctly printed in color.
Suggestions? Thanks ;)
You will have to change the constructors of your VerticalTextView to the following:
private int col = 0xFFFFFFFF;
public VerticalTextView(Context context, AttributeSet attrs)
{
super(context, attrs); // was missing a parent
col = getCurrentTextColor();
}
Then add
textPaint.setColor(col);
to your onDraw() function.
Hope this helps.
i think you can get color in:
**public VerticalTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}**
then set this color to textPaint.
Related
I have a menu activity that gets user setting of font and size and line spacing of text in all of TextView's, so i need a CustomTextView class to set these changes but my custom TextView does't work and give inflate Exception in logcat window. tank's a lot for your helps!
my CustomTextView:
package com.niloo.test2;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
public class CustomTextView extends TextView {
Context context;
SharedPreferences shp = context.getSharedPreferences("text", Context.MODE_PRIVATE);
int size = shp.getInt("size", 22);
int fasle = shp.getInt("fasle", 1);
String font = shp.getString("font", "bmitra");
public CustomTextView(Context context) {
super(context);
if (!isInEditMode())
setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/"+font));
setTextSize(size);
setLineSpacing(fasle, 1);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
if (! isInEditMode())
setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/"+font));
setTextSize(size);
setLineSpacing(fasle, 1);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (!isInEditMode())
setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/"+font));
setTextSize(size);
setLineSpacing(fasle, 1);
}
protected void onDraw (Canvas canvas) {
super.onDraw(canvas);
}
}
my XML code:
<com.niloo.test2.CustomTextView
android:id="#+id/tv_onv_amoozsh"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_vertical|center_horizontal"
android:layout_marginTop="10dp"
android:layout_weight="0.5"
android:textColor="#color/sabz_lajani"
android:textSize="25sp"
android:textStyle="bold" />
<com.niloo.test2.CustomTextView
android:id="#+id/tv_num_amoozsh"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_vertical|center_horizontal"
android:layout_marginBottom="2dp"
android:layout_weight="0.75"
android:textColor="#color/sabz_lajani"
android:textSize="35sp" />
and my main class:
final CustomTextView tv_onv_amoozsh= (CustomTextView) findViewById(R.id.tv_onv_amoozsh);
tv_onv_amoozsh.setText("page");
final CustomTextView tv_num_amoozsh=(CustomTextView) findViewById(R.id.tv_num_amoozsh);
tv_num_amoozsh.setText(sfhe_num);
LogCat Error:
02-03 22:41:38.329: E/AndroidRuntime(19952): FATAL EXCEPTION: main
02-03 22:41:38.329: E/AndroidRuntime(19952): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.niloo.test2/com.niloo.test2.MainActivity}: android.view.InflateException: Binary XML file line #143: Error inflating class com.niloo.test2.CustomTextView
The problem is most likely that you're initializing shp, size, fasle, and font outside of the constructor. These initializations happen before any constructor code is run. context is never set and is null when getSharedPreferences is called on it.
Try this:
public class CustomTextView extends TextView {
private SharedPreferences shp;
private int size;
private int fasle;
private String font;
public CustomTextView(Context context) {
super(context);
init(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
if (isInEditMode()) {
return;
}
shp = context.getSharedPreferences("text", Context.MODE_PRIVATE);
size = shp.getInt("size", 22);
fasle = shp.getInt("fasle", 1);
font = shp.getString("font", "bmitra");
setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/" + font));
setTextSize(size);
setLineSpacing(fasle, 1);
}
}
Do you have this at the first view in your layout?
xmlns:custom="http://schemas.android.com/apk/res-auto"
Please post the full layout file (reduce it in your project to the minimum that is still failing. Maybe only have one view in it - your custom text )
EDIT:
The xml code you posted is invalid. Here is the fixed version that should work (do not omit "http://", remove semicolons)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/sabzabi_kmrng"
android:gravity="top"
android:orientation="vertical"
tools:context="com.niloo.test2.MainActivity">
</LinearLayout>
The error is coming from this line:
setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/"+font));
Here we don't need to mention the keyword "fonts/" for path, because getAssets() method giving the route path of assets folder. So you can directly give font name like below:
setTypeface(Typeface.createFromAsset(context.getAssets(), font));
New to Android development, and I'm having trouble doing a simple drawing to a view using a canvas.
From what I've understood, something like this:
import android.content.Context;
import android.graphics.Canvas;
import android.view.View;
public class DrawView extends View
{
public DrawView(Context context)
{
super(context);
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
canvas.drawRGB(255,0,0);
}
}
With this as my Activity:
public class Prototype1 extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
And this for the layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<com.dhs2.prototype1.DrawView
android:id="#+id/map"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
Should just draw red everywhere, but instead I just get a blank screen.
Any idea where I'm going wrong?
Since you added your custom view in an XML layout file, you should add 2 more constructors:
public DrawView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
}
This is because you pass some attributes to the view, like fill_parent, wrap_content, so the constructor public DrawView(Context context) won't be called.
This would work however, if you won't declare your custom view in the XML layout file, but setting it directly from the onCreate() like this:
setContentView(new DrawView(this));
I have a GraphicsView class that extends from the View class and I want to add this GraphicsView class to the main layout in my project. How can I do that?
static public class GraphicsView extends View {
public GraphicsView(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
// Drawing commands go here
Path rect = new Path();
rect.addRect(100, 100, 250, 50, Direction.CW);
Paint cPaint = new Paint();
cPaint.setColor(Color.LTGRAY);
canvas.drawPath(rect, cPaint);
}
}
and my main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linnnnlayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello" />
<TextView
android:id="#+id/Customfont"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello" />
<View
android:id="#+id/view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
You need to give complete path of your class that extends View,
<com.blah.blah.GraphicsView
android:id="#+id/view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
If I remember correctly, you need to provide more constructors to use view from xml file (add it to xml file like "Me and We" suggested).
public GraphicsView(Context context) {
super(context);
}
public GraphicsView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GraphicsView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
Update: fixed code.
i finaly got it here is the code
the XML code
<com.customfonts.namespace.BreakDownBar
android:id="#+id/gview"
android:layout_width="fill_parent"
android:layout_height="20dip"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:background="#color/BreakDownBarBack"/>
and the class
package com.customfonts.namespace;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.util.AttributeSet;
import android.view.View;
public class BreakDownBar extends View {
public BreakDownBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
//Draw rectangle;
Path rect = new Path();
rect.addRect(0, 0,250, 150,Direction.CW);
Paint cpaint = new Paint();
cpaint.setColor(Color.GREEN);
canvas.drawPath(rect, cpaint);
}
}
you need to do this:
LinearLayout v = (LinearView) findViewById(R.id.linnnnlayout);
GraphicsView myView = new myGraphicsView(this);
v.addView(myView);
Because your custom View is an inner class in your Activity the java compiler will output the name ActivityName$GraphicsView for that class. You can't use that name directly as the View name in the xml layout because of the $ character but you can do it like this:
<view
class="com.package.here.ActivityName$GraphicsView"
android:id="#+id/view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
where ActivityName is the name of the activity where your GraphicsView class is declared.
public class MainActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout v = (LinearLayout) findViewById(R.id.linearLayout);
MyGraphics myView = new MyGraphics(this);
v.addView(myView);
}
}
public class MyGraphics extends View {
public MyGraphics(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
// Drawing commands go here
Path rect = new Path();
rect.addRect(100, 100, 250, 50, Direction.CW);
Paint cPaint = new Paint();
cPaint.setColor(Color.LTGRAY);
canvas.drawPath(rect, cPaint);
}
}
XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:id="#+id/linearLayout">
<TextView
android:id="#+id/Customfont"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello" />
</LinearLayout>
This is working for me and add the view in XML with full path and try giving wrapcontent for height and width.
public class RectangleView extends View {
public RectangleView(Context context) {
super(context);
}
public RectangleView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RectangleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.GRAY);
canvas.drawColor(Color.BLUE);
canvas.drawRect(10,10,50,50, paint);
}
}
I know Spannable can help me color any specific letters in a textview. However, is it possible to color 1/2 or 1/3 of a letter. I wanted to color text within a textview by percentage instead of by letter. Thanks for reading, and please let me know if you had some idea or solution to this.
thanks
It may be easier to use Spanned thought android.text.HTML
So something like this:
Spanned text = HTML.fromHtml("Sp<span style=\"color:red\">ann</span>able");
textView.setText(text);
It can also be used to add images, but it a bit more complicated.
UPDATE
I re-read your question and thought of a solution. You could create a custom view that has two textViews in a FrameLayout (on top of each other) and then resize the one on the top relative to the percentage. Something like this:
import android.content.Context;
import android.content.res.ColorStateList;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.TextView;
public class ProgressTextView extends FrameLayout {
private TextView backgroundTextView;
private TextView foregroundTextView;
private CharSequence text;
private ProgressTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private ProgressTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private ProgressTextView(Context context) {
super(context);
init(context, null);
}
private void init(Context context, AttributeSet attrs) {
backgroundTextView = new TextView(context);
foregroundTextView = new TextView(context);
addView(backgroundTextView);
addView(foregroundTextView);
// process custom attributeSet from xml to set the colours
}
public void setBackgroundTextColor(int color) {
backgroundTextView.setTextColor(color);
}
public void setBackgroundTextColor(ColorStateList colors) {
backgroundTextView.setTextColor(colors);
}
public void setForegroundTextColor(int color) {
backgroundTextView.setTextColor(color);
}
public void setForegroundTextColor(ColorStateList colors) {
backgroundTextView.setTextColor(colors);
}
public void setPercentage(float per) {
foregroundTextView.setWidth((((float) backgroundTextView.getWidth()) / 100f) * per);
}
public void setText(CharSequence text) {
this.text = text;
backgroundTextView.setText(text);
foregroundTextView.setText(text);
}
public CharSequence getText() {
return text;
}
}
PS: not tested ;) just an idea
MORE UPDATE
Apparently, with this method the text gets shortened instead of just cropped as I expected. The maybe on creation of the foregroundTextView you could do this:
foregroundTextView = new TextView(context) {
#Override
protected void onDraw (Canvas canvas) {
super.onDraw(canvas);
Rect bounds = canvas.getClipBounds();
bounds.right (((float) bounds.right) / 100.0f) * per;
canvas.clipRect(bounds);
}
};
And also add the per variable and modify setPercentage(float per) to be just a setter:
private float per = 0.0f;
public void setPercentage(float per) {
this.per = per;
}
Hope this one works ;)
You could draw the letters yourself on a canvas. Each letter consisting of a bunch of interconnected arcs, that way you could style each individually.
Having to draw each letter would be considerably painstaking though, e.g., paint.setColor(), canvas.drawArc(), paint.setColor(), canvas.drawArc(), and so on...
create a drawable and override it's onDraw method and paint canvas how you wish and set it as background to your textview
Having a problem with Android Custom components. Trying to draw an oval shape but nothing happening.
I have this line in layout xml file
<android.project.realtimedata.DemoView android:id="#+id/demoView"
android:layout_width="fill_parent" android:layout_height="wrap_content" />
Here is the code for my custom component class.
package android.project.realtimedata;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.util.AttributeSet;
import android.view.View;
public class DemoView extends View{
ShapeDrawable thisGauge = null;
public DemoView(Context context){
super(context);
init();
}
public DemoView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
private void init(){
int x = 10;
int y = 10;
int width = 300;
int height = 50;
thisGauge = new ShapeDrawable(new OvalShape());
thisGauge.getPaint().setColor(0xff74AC23);
thisGauge.setBounds(x, y, x + width, y + height);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
thisGauge.draw(canvas);
}
}
I also have this line in onCreate method of Activity
demoView = (DemoView) findViewById(R.id.demoView);
Whenever I launch the application the custom component is not there.
I tried looking at it from LogCat and it definitely gets created.
What am I missing here?
Thanks in advance.
Make sure that you calling findViewById(R.id.demoView) after calling setContentView(...). To ensure that your view is being inflated, you can call Log.d("DemoView", "Created") from inside your DemoView constructor.