android - 将当前 TextView 内容绘制到 Bitmap

标签 android bitmap scroll textview

我在 ScrollView 中有一个 TextView:

<?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 有很多文本,这就是为什么它是可滚动的。我需要将 TextView 中当前可见的内容绘制到 Bitmap 中。出于测试目的,我在 ImageView 中显示此位图。我有以下代码:

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());
    }
}

问题是,一旦我滚动 TextView(触发 TouchEvent),Bitmap 就不会反射(reflect) TextView 的当前内容,而总是只有 TextView 的开始内容(当前滚动位置是什么无关紧要)。我更新了帖子以提供工作代码 - 也许它会在某人的其他设备上工作。

更新

我还尝试通过覆盖自定义 TextView 中的 onDraw 来检查 WarrenFaith 的想法,但它仍然只绘制 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);

    }
}

最佳答案

尝试覆盖 TextViewonDraw() 方法应该有效。在那里您可以根据 canvas 参数创建位图。详情可以看我的教程:How to create and save a screenshot from a SurfaceView

更新:
我解决了你的问题:

Activity (我更改了 Handler 用法并删除了一些方法。基本上我稍微缩减​​了代码)。

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());
    }
}

自定义 TextView :重要:诀窍是获取滚动位置!

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:(我删除了 ScrollView 并让 TextView 处理滚动)

<?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>

关于android - 将当前 TextView 内容绘制到 Bitmap,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10677799/

相关文章:

java - TextureView:在后台执行 TextureView.getBitmap()

scroll - 基于列表的ListView的溢出

android - 对溢出菜单项使用自定义 View

android - 使用多线程绘制位图,在 Windows 和 Android 中结果不同

java - 从 AsyncTask 返回位图

jquery - 固定 div 的 css 垂直滚动

css - 这是在我的网站上放置滚动社交栏的好方法吗?

php - 在循环中执行网络调用后,同一项目被删除两次

android - RxJava 同时删除操作

android - 用于 libGDX 的 AnalogOnScreenController 或 Joystick