I have a TextView which contains dynamic text (of varying length). In order to enable smooth pinch and zoom, I would like to convert this TextView to an ImageView and display that ImageView instead of the TextView. So I tried to set up the TextView programmcially like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song_view);
String text = getIntent().getStringExtra(SongbookListFragment.SONG_TEXT_ARGS);
song_textview = new AppCompatTextView(this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
song_textview.setLayoutParams(layoutParams);
song_textview.setPadding(PADDING,PADDING,PADDING,PADDING);
song_textview.setText(Html.fromHtml(text));
song_textview.setTextColor(Color.BLACK);
song_textview.setBackgroundColor(Color.TRANSPARENT);
song_textview.setHorizontallyScrolling(true);
song_textview.setTextSize(16);
}
My song_view.xml uses the zoomable PhotoView which extends ImageView:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<com.github.chrisbanes.photoview.PhotoView
android:id="#+id/imageview_songtext"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</ScrollView>
Now in onWindowFocusChanged method of the activity, I convert the TextView to a Bitmap and display it within the PhotoView like this:
#Override
public void onWindowFocusChanged(boolean hasFocus){
super.onWindowFocusChanged(hasFocus);
int width = this.getWindow().getDecorView().getWidth();
int height = this.getWindow().getDecorView().getHeight();
Bitmap bitmapHolder = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bitmapHolder);
if (song_textview != null) {
song_textview.layout(0, 0, width, height);
song_textview.draw(c);
PhotoView songPhotoView = findViewById(R.id.imageview_songtext);
songPhotoView.setImageBitmap(bitmapHolder);
}
}
This works well except that I do not know how to set the height of the Bitmap within onWindowFocusChanged. If I use this.getWindow().getDecorView().getHeight() like in my code sample above, the length of the text is cut because this.getWindow().getDecorView().getHeight() returns the screen height and not the actual height of the TextView. Of course, the TextView is not added to the layout which is why there is no measured height. So how can I get the full length of the TextView to display it in my Bitmap?
Just call below setText method.
public void setText(String text){
Paint paint = new Paint();
paint.setTextSize(30);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
Rect result = new Rect();
paint.getTextBounds(text, 0, text.length(), result);
int width= result.width();
//background color red
int color=Color.RED;
Bitmap img=drawText(text, width, color);
songPhotoView.setImageBitmap(img);
//background transparent
int colorT=Color.TRANSPARENT;
Bitmap img1=drawText(text,width,colorT);
songPhotoView.setImageBitmap(img1);
}
public Bitmap drawText(String text, int textWidth, int color) {
// Get text dimensions
TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
textPaint.setStyle(Paint.Style.FILL);
textPaint.setColor(Color.parseColor("#ff00ff"));
textPaint.setTextSize(30);
StaticLayout mTextLayout = new StaticLayout(text, textPaint, textWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
// Create bitmap and canvas to draw to
Bitmap b = Bitmap.createBitmap(textWidth, mTextLayout.getHeight(), Bitmap.Config.ARGB_4444);
Canvas c = new Canvas(b);
// Draw background
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setColor(color);
c.drawPaint(paint);
// Draw text
c.save();
c.translate(0, 0);
mTextLayout.draw(c);
c.restore();
return b;
}
Related
I would like to convert text into bitmap, coded as follows:
Code:
public Bitmap convertTextToBM(String strength, int maxWidth, int maxHeight, String text)
{
TextView tv = new TextView(this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(maxWidth, maxHeight);
tv.setLayoutParams(layoutParams);
tv.setText(""+text);
tv.setTextColor(Color.BLACK);
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, (maxHeight/2));
//strength
if (strength.equals("bold"))
{
tv.setTypeface(null, Typeface.BOLD);
}
tv.setGravity(Gravity.CENTER);
Bitmap testB = Bitmap.createBitmap(maxWidth, maxHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(testB);
tv.layout(0, 0, maxWidth, maxHeight);
tv.draw(c);
return testB;
}
Screenshot:
Question:
How to make the text drawn at center of the available space? Thanks!
One thing you can do is to try to create this in XML. Try to set the gravity to CENTER_VERTICAL | CENTER_HORIZONTAL, but the other thing is, when you create the XML, you can set the layout_gravity to CENTER_VERTICAL | CENTER_HORIZONTAL (you can do it through code as well but it's more complicated).
Instead of
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(maxWidth, maxHeight);
tv.setLayoutParams(layoutParams);
tv.setGravity(Gravity.CENTER);
Use
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(layoutParams);
tv.setGravity(Gravity.CENTER_VERTICAL |Gravity.CENTER_HORIZONTAL);
I have used another method to achieve a similar effect:
public Bitmap drawText(int textSize, String textColor, String strength, int textWidth, int maxHeight, String text)
{
TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG| Paint.LINEAR_TEXT_FLAG);
textPaint.setStyle(Paint.Style.FILL);
textPaint.setAntiAlias(true);
textPaint.setColor(Color.BLACK);
//strength
if (strength.equals("bold"))
{
textPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
}
textPaint.setTextSize(textSize);
StaticLayout mTextLayout = new StaticLayout(text, textPaint, textWidth, Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
// Create bitmap and canvas to draw to
Bitmap b = Bitmap.createBitmap(textWidth, mTextLayout.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
// Draw background
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
paint.setStyle(Paint.Style.FILL);
c.drawPaint(paint);
// Draw text
c.save();
c.translate(0, 0);
mTextLayout.draw(c);
c.restore();
return b;
}
Im trying to draw a string on top of an Image,The code works but the transparency is not obtained i have used several values for alpha,but does not work.
paint.setAlpha(alpha);
Can some one tell me what are the range of values for transparency or what im doing wrong here
public static Bitmap drawtext(Bitmap src, String txt,int alpha) {
int w = src.getWidth();
int h = src.getHeight();
Bitmap result = Bitmap.createBitmap(w, h, src.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(src, 0, 0, null);
Paint paint = new Paint();
paint.setAlpha(alpha);
paint.setColor(Color.RED);
paint.setTextSize(18);
paint.setAntiAlias(true);
paint.setUnderlineText(true);
canvas.drawText(txt, 20, 25, paint);
return result;
}
See:
http://developer.android.com/reference/android/graphics/Paint.html#setColor(int)
The setColor will overwrite the alpha value you just set before that call. That should work:
paint.setColor(Color.RED);
paint.setAlpha(alpha);
Try this code or download demo here
public Bitmap drawText(String text, int textWidth, int color) {
// Get text dimensions
TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
textPaint.setStyle(Paint.Style.FILL);
textPaint.setColor(Color.parseColor("#ff00ff"));
textPaint.setTextSize(30);
StaticLayout mTextLayout = new StaticLayout(text, textPaint, textWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
// Create bitmap and canvas to draw to
Bitmap b = Bitmap.createBitmap(textWidth, mTextLayout.getHeight(), Bitmap.Config.ARGB_4444);
Canvas c = new Canvas(b);
// Draw background
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setColor(color);
c.drawPaint(paint);
// Draw text
c.save();
c.translate(0, 0);
mTextLayout.draw(c);
c.restore();
return b;
}
set the returned image to imageview
//background transparent
int colorT=Color.TRANSPARENT;
Bitmap img1=drawText(text,width,colorT);
img2.setImageBitmap(img1);
I have a simple activity with a green background and I am trying to provide a red overlay with a transparent circular area. Here is the effect I am trying to accomplish:
Expected Image
With the code I have found on the internet, this is what I see:
Result of code
What appears to be happening is PorterDuff applies itself to all views in the activity instead of the one that I distinctly tell it to. Many of the posts on Stack have been about masking a bitmap with another bitmap and I am trying to mask an part of a view with a programmatically created circular shape. Here is the code I am attempting to use:
public class ClippingTestActivity extends Activity {
private Paint mPaint;
ClippingView ddd;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.test);
View v = new View(this.getBaseContext());
v.setBackgroundColor(Color.GREEN);
this.addContentView(v, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
ClippingView r = new ClippingView(this.getBaseContext());
r.setBackgroundColor(Color.RED);
this.addContentView(r, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
}
}
public class ClippingView extends View {
Paint paint = new Paint();
Path path = new Path();
public ClippingView(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw( canvas );
paint.setColor(Color.TRANSPARENT);
paint.setStyle(Style.FILL);
paint.setXfermode( new PorterDuffXfermode( Mode.CLEAR ) );
int cx = 200;
int cy = 200;
int radius = 50;
canvas.drawCircle( cx, cy, radius, paint );
}
}
with the layout xml file being as such
<?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/com.appspot.scruffapp"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:background="#ff0000">
</RelativeLayout>
Does anyone know how to accomplish the effect?
Okay. With the help of a friend I figured it out. Turns out I needed to create a new canvas that was empty and pass that around from function to function and draw the canvas on a new view which gets added later. This is the code that worked for me:
Bitmap circle = DrawView.makeCircle(drawable);
Bitmap overlayBg = DrawView.makeOverlayBg(canvas.getWidth(),canvas.getHeight());
Bitmap finalImage = Bitmap.createBitmap(canvas.getWidth(),canvas.getHeight(), Bitmap.Config.ARGB_8888);
final android.graphics.Canvas tmpCanvas = new android.graphics.Canvas(finalImage);
tmpCanvas.drawBitmap(overlayBg, 0, 0, null);
final android.graphics.Paint paint = new android.graphics.Paint();
paint.setXfermode(new android.graphics.PorterDuffXfermode(Mode.DST_OUT));
tmpCanvas.drawBitmap(circle, cx - radius, cy - radius, paint);
canvas.drawBitmap(finalImage, 0, 0, null);
I have the following code to draw text.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setTextSize(400);
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);
paint.setTextAlign(Align.LEFT);
paint.setStyle(Style.FILL);
String text = "698";
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
int textWidth = bounds.width();
int textHeight = bounds.height();
Bitmap originalBitmap = Bitmap.createBitmap(textWidth,
textHeight, Bitmap.Config.ARGB_8888);
Canvas singleUseCanvas = new Canvas(originalBitmap);
singleUseCanvas.drawColor(Color.BLUE);
singleUseCanvas.drawText(text, 0, textHeight, paint);
canvas.drawBitmap(originalBitmap, 0, 0, null);
}
I am getting undesired outcome, which its right and bottom sides are being cropped.
I avoid right side cropping, by using
float textWidth = paint.measureText(text);
Bitmap originalBitmap = Bitmap.createBitmap((int)(textWidth + 0.5),
textHeight, Bitmap.Config.ARGB_8888);
I am getting the following improvement
Yet. My bottom still being cropped. May I know what is the correct way to obtained rendered text height, which is analogy to rendered text width using paint.measureText?
I think i would be helpful to have a look at this post:
Android Paint: .measureText() vs .getTextBounds()
It have a good survey about sizing of rendered text and also text height which is your concern.
I want to sketch a graph that track the user weight progress,
I am writing a method that I can call in the onCreat event,
this is my code:
public void drawGraph(){
Display display = getWindowManager().getDefaultDisplay();
private int width = display.getWidth();
private int height = display.getHeight();
Paint paint = new Paint();
Canvas canvas =new Canvas();
paint.setColor(Color.GRAY);
canvas.drawLine(0, 0, 0, height, paint); // the x-axes represent the date
canvas.drawLine(0, height, width, height, paint); // the y-axes represent the weight
paint.setColor(Color.RED);
canvas.drawLine(0, max, width, max, paint); //draw the maximum healthy weight
paint.setColor(Color.YELLOW);
canvas.drawLine(0, min, width, min, paint); // draw the minimum healthy weight
paint.setColor(Color.GREEN);
canvas.drawLine(0, gW, width, gW, paint); // draw the goal weight
int xDis = width/weekNumbers;
int y;
Path path = new Path();
for (int i = 0; i <= Weightvalues; i++){
Cursor c = db.rawQuery("SELECT CURRENTWEIGHT FROM WEIGHT WHERE DATECREATED > " + startDate, null);
int weight;
if (c!=null){
if (c.moveToFirst()){
do{
weight = c.getInt(0);
// I want now to find out for each entry the point represent it on the graph
y = Math.round(weight * y / range); //range is the difference between the maximum weight and the minimum weight
if (i==1)
path.moveTo(0, y);
else
path.lineTo(0 + i*xDis, height-y);
}while(c.moveToNext());
}
}
}
paint.setColor(Color.BLUE);
canvas.drawPath(path, paint);
}
this is the onCreat event
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.weight_chart);
helper = new DataBaseHelper(this);
drawGraph();
}
when i run the program i faced this error
ERROR/AndroidRuntime(738): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{*********.WeightChart}: java.lang.NullPointerException
Can any body review it for me and tell me where i went wrong
Best regards
You seem to use Canvas without assigning it a Bitmap to do drawing onto. To get your image on screen, one way is to define ImageView in your layout xml;
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/graph_image" />
Accompanied with following changes to your drawGraph method;
...
Bitmap bitmap = BitmapCreateBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas = new Canvas(bitmap);
...
Do your drawing stuff..
...
ImageView iv = (ImageView)findViewById(R.id.graph_image);
iv.setImageBitmap(bitmap);
}