当前位置: 首页 > 知识库问答 >
问题:

从FrameLayout生成GIF

陆宏扬
2023-03-14

嗨,我试图从动画视图生成gif

简而言之,我在FrameLayout中有了ImageView和动画视图,现在我想生成主FrameLayout的gif,最低sdk级别19。getDrawingCache位图并将它们按顺序排列成gif可能会导致内存越界问题。

当我点击“开始录制”时,我想要特定视图的gif或视频。

共有1个答案

寇涵容
2023-03-14

首先,您需要实现这些库:

implementation 'com.blankj:utilcodex:1.30.6'
implementation 'com.waynejo:androidndkgif:0.3.3'
implementation 'com.jiang.android.observablescheduler:schedule:1.0.1'
  1. 第一个是一个有用的库,它包含所有必要的类来帮助您,例如(ImageUtilsPathUtils…)
  2. 第二个用于GIF的编码和解码
  3. 第三个是用java.util.concurrent替换AsyncTask

XML:我试图做和你一样的事情:

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:gravity="center"
        android:orientation="vertical">

        <RelativeLayout
            android:id="@+id/viewToBeRecorded"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:layout_gravity="center"
            android:background="@android:color/holo_green_light"
            android:gravity="center">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:gravity="center"
                android:text="View To Be Recorded"
                android:textStyle="bold" />
        </RelativeLayout>

        <Button
            android:id="@+id/changeBg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Change Background"
            android:textStyle="bold" />

        <Button
            android:id="@+id/startRecord"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Start Record"
            android:textStyle="bold" />

        <Button
            android:id="@+id/stopRecord"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:enabled="false"
            android:text="Stop Record"
            android:textStyle="bold" />
    </LinearLayout>

爪哇岛:

public class MainActivity extends AppCompatActivity {
    
    private Button changeBg, startRecord, stopRecord;
    private RelativeLayout viewToBeRecorded;
    private boolean isRecording = false;
    private GifEncoder mGifEncoder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initializeViews();

        startRecord.setOnClickListener(v -> {
            isRecording = true;
            ToastUtils.showShort("Start recording...");
            startRecord.setEnabled(false);
            stopRecord.setEnabled(true);
            generateGIF();
        });

        stopRecord.setOnClickListener(v -> {
            isRecording = false;
            ToastUtils.showShort("Stop recording...");
            startRecord.setEnabled(true);
            stopRecord.setEnabled(false);
        });

        changeBg.setOnClickListener(v -> {
            Random rnd = new Random();
            int color = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
            viewToBeRecorded.setBackgroundColor(color);
        });

    }

    private void generateGIF() {
        JObservable.create((JObservable.OnSubscribe<String>) mSubscriber -> {
            try {
                File storageDir = new File(PathUtils.getExternalPicturesPath() + "/GIFs");
                FileUtils.createOrExistsDir(storageDir);
                File gifFile = new File(storageDir, "GIF" + System.currentTimeMillis() + ".gif");
                String outputPath = gifFile.getAbsolutePath();
                Bitmap firstFrame = ImageUtils.view2Bitmap(viewToBeRecorded);
                try {
                    mGifEncoder.init(firstFrame.getWidth(), firstFrame.getHeight(), outputPath, GifEncoder.EncodingType.ENCODING_TYPE_SIMPLE_FAST);
                    while (isRecording) {
                        Bitmap frame = ImageUtils.view2Bitmap(viewToBeRecorded);
                        mGifEncoder.encodeFrame(frame, 100);
                        Thread.sleep(20);
                    }
                    mGifEncoder.close();
                    mSubscriber.notifyData(outputPath);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            } catch (Exception e) {
                mSubscriber.error(e);
            }
        }).workedOn(Schedules.background())
                .subscribeOn(Schedules.mainThread())
                .subscribe(new Subscriber<String>() {
                    @Override
                    public void notifyData(String outputPath) {
                        FileUtils.notifySystemToScan(outputPath);
                        ToastUtils.showShort("GIF saved!");
                    }

                    @Override
                    public void error(Throwable t) {
                        Log.e("View2GIF", "generateGIF throw error : " + t.getMessage());
                    }
                });

    }

    private void initializeViews() {
        viewToBeRecorded = findViewById(R.id.viewToBeRecorded);
        changeBg = findViewById(R.id.changeBg);
        stopRecord = findViewById(R.id.stopRecord);
        startRecord = findViewById(R.id.startRecord);
        mGifEncoder = new GifEncoder();
    }

输出:

别忘了添加:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

并确保授予存储权限

 类似资料:
  • 6.2.3.FrameLayout FrameLayout(帧布局)将其下的子元素相互覆盖起来,就像一副扑克牌,只留一个显示在外面。它可以用于标签的实现,也可以作为以后要用的控件的临时存放地。

  • 虽然使用GraphiQL效果很好,但我的老板要求我实现一个用户界面,用户可以通过诸如checkbox、map relationships之类的UI元素检查呈现给他们的元素,并获取数据,这样做将为用户生成GraphiQL输入,调用API并将结果返回给用户。 所以,基本上这涉及到两代人。从GraphQL模式生成用户界面,并从用户的选择生成GraphQL输入查询。 我搜索了一下,但没有找到任何工具已经做

  • 问题内容: 是否有可能从byte []生成java.security.cert.X509Certificate? 问题答案: 当然。 证书对象可以由CertificateFactory的一个实例创建- 尤其是配置为创建X509证书的一个实例。可以这样创建: 然后,您需要向其传递一个包含证书字节的InputStream。这可以通过将字节数组包装在ByteArrayInputStream中来实现:

  • 问题内容: 我正在尝试在给定私钥和已知曲线的情况下生成公钥。下面是我的代码: 但是,当我打电话给 我时:我得到了例外:(不是我的拼写错误) 我似乎在计算错误,但是我不确定错误在哪里。 谢谢您的帮助! 问题答案: 如果我未来的自己需要解决方案:

  • 我是编程新手。我在使用GraphicalLayout,然后当我阅读xml文件时,我看到了FrameLayout。然后我搜索了一下,但找不到有用的东西。什么是FrameLayout?它做什么?