Drawing the current contents of a TextView in Bitmap

I have a TextView in a ScrollView:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/parentLayout" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ScrollView android:id="@+id/textAreaScroller" android:layout_width="400px" android:layout_height="200px" android:layout_x="0px" android:layout_y="25px" android:fadeScrollbars="false" android:scrollbarSize="3px" android:scrollbarStyle="insideOverlay" > <TextView android:id="@+id/scrapbook" android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="" /> </ScrollView> <Button android:id="@+id/upBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Up" /> <Button android:id="@+id/downBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Down" /> <ImageView android:id="@+id/imageView" android:layout_width="400px" android:layout_height="200px" /> </LinearLayout> 

TextView has a lot of text, so it scrolls. I need to draw the current visible content in a TextView in Bitmap. For testing, I display this bitmap in an ImageView. I have the following code:

 public class TextviewToImageActivity extends Activity { private TextView textView; private ScrollView textAreaScroller; private ImageView imageView; private Handler mHandler; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mHandler = new Handler(); imageView = (ImageView) findViewById(R.id.imageView); textAreaScroller = (ScrollView) findViewById(R.id.textAreaScroller); textView = (TextView) findViewById(R.id.scrapbook); textView.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { imageView.setImageBitmap(loadBitmapFromView(textAreaScroller)); return false; } }); Button upBtn = (Button) findViewById(R.id.upBtn); Button downBtn = (Button) findViewById(R.id.downBtn); upBtn.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { scheduleScroller(upScroller); imageView.setImageBitmap(loadBitmapFromView(textView)); } else if (event.getAction() == MotionEvent.ACTION_UP) { mHandler.removeMessages(1); } return true; } }); downBtn.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { scheduleScroller(downScroller); imageView.setImageBitmap(loadBitmapFromView(textView)); } else if (event.getAction() == MotionEvent.ACTION_UP) { mHandler.removeMessages(1); } return true; } }); loadDoc(); } private Runnable downScroller = new Runnable() { public void run() { textAreaScroller.scrollBy(0, 10); scheduleScroller(downScroller); } }; private Runnable upScroller = new Runnable() { public void run() { textAreaScroller.scrollBy(0, -10); scheduleScroller(upScroller); } }; private void scheduleScroller(Runnable scrollerJob) { Message msg = Message.obtain(mHandler, scrollerJob); msg.what = 1; mHandler.sendMessageDelayed(msg, 10); } private static Bitmap loadBitmapFromView(View v) { Bitmap b = Bitmap.createBitmap(400, 200, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(b); v.draw(c); return b; } private void loadDoc() { String s = ""; for (int x = 0; x <= 100; x++) { s += "Line: " + String.valueOf(x) + "\n"; } textView.setText(s); textView.setMovementMethod(new ScrollingMovementMethod()); } } 

The problem is that as soon as I scroll through the TextView (trigger TouchEvent), the bitmap does not reflect the current contents of the TextView and instead always has only the initial contents of the TextView (no matter what the current scroll position is). I updated the message to provide a working code - maybe it will work on another device.

UPDATE

I also tried to test the idea of ​​WarrenFaith by overriding onDraw in my custom TextView, but somehow it only draws the initial content of the TextView:

 public class MyTextView extends TextView { private Bitmap mBitmap; public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); } public MyTextView(Context context) { super(context); } public MyTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public Bitmap getBitmap() { return mBitmap; } @Override protected void onDraw(Canvas canvas) { mBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight() , Bitmap.Config.ARGB_8888); Canvas c = new Canvas(mBitmap); super.onDraw(canvas); super.onDraw(c); } } 
+4
source share
1 answer

Trying to override the onDraw() method of the TextView should work. There you can create a bitmap based on the canvas parameter. Details can be found in my tutorial: How to create and save a screenshot from SurfaceView

Update:
I fixed your problem:

Activity (I changed the use of Handler and removed some methods. Basically I cut the code a bit).

 import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.text.method.ScrollingMovementMethod; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.Button; import android.widget.ImageView; /** * @author WarrenFaith */ public class TextToImageActivity extends Activity { private MyTextView textView; private ImageView imageView; private boolean mRepeatDrawing = false; private Handler mHandler; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.textview); mHandler = new Handler(); imageView = (ImageView) findViewById(R.id.imageView); textView = (MyTextView) findViewById(R.id.scrapbook); Button upBtn = (Button) findViewById(R.id.upBtn); Button downBtn = (Button) findViewById(R.id.downBtn); upBtn.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { mRepeatDrawing = true; mHandler.post(upScroller); } else if (event.getAction() == MotionEvent.ACTION_UP) { mRepeatDrawing = false; } return false; } }); downBtn.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { mRepeatDrawing = true; mHandler.post(downScroller); } else if (event.getAction() == MotionEvent.ACTION_UP) { mRepeatDrawing = false; } return false; } }); loadDoc(); } private Runnable downScroller = new Runnable() { public void run() { textView.scrollBy(0, 10); imageView.setImageBitmap(textView.getBitmap()); if (mRepeatDrawing) { mHandler.postDelayed(this, 10); } } }; private Runnable upScroller = new Runnable() { public void run() { textView.scrollBy(0, -10); imageView.setImageBitmap(textView.getBitmap()); if (mRepeatDrawing) { mHandler.postDelayed(this, 10); } } }; private void loadDoc() { String s = ""; for (int x = 0; x <= 100; x++) { s += "Line: " + String.valueOf(x) + "\n"; } textView.setText(s); textView.setMovementMethod(new ScrollingMovementMethod()); } } 

Custom text view: Important: the trick was to get the scroll position!

 import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.util.AttributeSet; import android.widget.TextView; /** * @author WarrenFaith */ public class MyTextView extends TextView { private Bitmap mBitmap; public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); } public MyTextView(Context context) { super(context); } public MyTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public Bitmap getBitmap() { return mBitmap; } @Override protected void onDraw(Canvas canvas) { mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas c = new Canvas(mBitmap); c.translate(0, -getScrollY()); super.onDraw(c); super.onDraw(canvas); } } 

xml: (I removed ScrollView and let TextView handle scrolling)

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/parentLayout" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <com.testproject.MyTextView android:id="@+id/scrapbook" android:layout_width="400px" android:layout_height="200px" android:scrollbars="vertical" android:scrollbarSize="3px" android:text="" android:background="#0000ff" /> <Button android:id="@+id/upBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Up" /> <Button android:id="@+id/downBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Down" /> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 
+3
source

Source: https://habr.com/ru/post/1413442/


All Articles