jjzjj

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

coder 2023-12-14 原文

我在 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/

有关android - 将当前 TextView 内容绘制到 Bitmap的更多相关文章

  1. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  2. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  3. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

  4. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  5. ruby - 如何找到调用当前方法的方法 - 2

    如何找到调用此方法的位置?defto_xml(options={})binding.pryoptions=options.to_hifoptions&&options.respond_to?(:to_h)serializable_hash(options).to_xml(options)end 最佳答案 键入caller。这将返回当前调用堆栈。文档:Kernel#caller.例子[0]%rspecspec10/16|===================================================62=====

  6. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  7. ruby - 以毫秒为单位获取当前系统时间 - 2

    在Ruby中,以毫秒为单位获取自纪元(1970)以来的当前系统时间的正确方法是什么?我试过了Time.now.to_i,好像不是我想要的结果。我需要结果显示毫秒并且使用long类型,而不是float或double。 最佳答案 (Time.now.to_f*1000).to_iTime.now.to_f显示包含十进制数字的时间。要获得毫秒数,只需将时间乘以1000。 关于ruby-以毫秒为单位获取当前系统时间,我们在StackOverflow上找到一个类似的问题:

  8. ruby - 如何在ruby中提取方括号内的内容 - 2

    我正在尝试提取方括号内的内容。到目前为止,我一直在使用它,它有效,但我想知道我是否可以直接在正则表达式中使用某些东西,而不是使用这个删除功能。a="Thisissuchagreatday[coolawesome]"a[/\[.*?\]/].delete('[]')#=>"coolawesome" 最佳答案 差不多。a="Thisissuchagreatday[coolawesome]"a[/\[(.*?)\]/,1]#=>"coolawesome"a[/(?"coolawesome"第一个依赖于提取组而不是完全匹配;第二个利用前瞻和

  9. ruby-on-rails - 如何找出拦截 'method_missing' 的内容 - 2

    使用Ruby1.8.6/Rails2.3.2我注意到在我的任何ActiveRecord模型类上调用的任何方法都返回nil而不是NoMethodError。除了烦人之外,这还破坏了动态查找器(find_by_name、find_by_id等),因为即使存在记录,它们也总是返回nil。不从ActiveRecord::Base派生的标准类不受影响。有没有办法追踪在ActiveRecord::Base之前拦截method_missing的是什么?更新:切换到1.8.7后,我发现(感谢@MichaelKohl)will_paginate插件首先处理method_missing。但是will_pa

  10. ruby - 当前的 Ruby 方法是通过 super 调用的吗? - 2

    在运行时的方法中,有没有办法知道该方法是否已通过子类中的super调用?例如moduleSuperDetectordefvia_super?#whatgoeshere?endendclassFooincludeSuperDetectordefbarvia_super??'super!':'nothingspecial'endendclassFu"nothingspecial"Fu.new.bar#=>"super!"我如何编写via_super?,或者,如果需要,如何编写via_super?(:bar)? 最佳答案 可能有更好的方法

随机推荐