Wenn Sie eine Tutorial-App oder eine Art App erstellen, die das Programmieren lehrt, dann brauchen Sie ein natives Widget, das den Code nicht nur darstellen, sondern auch beleuchten kann. Ein solches Widget nennen wir Codeview und das ist es, was wir in diesem Tutorial behandeln. Wir sehen uns verschiedene Codeview-Bibliotheken und Beispiele an.

(a). CodeView

Code-Highlighter-Widget.

Hier sind die Eigenschaften dieses Widgets:

  • Powered by Highlight.js
  • 176 Sprachen und 79 Stile
  • Zeilenumbruch
  • Sprach-Erkennung
  • Zoom (Pinch-Geste)
  • Zeilennummer
  • Zeilenzahl
  • Aktuelle Zeile hervorheben (durch Klicken/Tippen)
  • Zeile hervorheben
  • Tippen Sie auf die Zeilen (erhalten Sie die Zeilennummer und Ihren Inhalt)

Hier ist eine einfache Demo:

Schritt 1: CodeView installieren

Diese Bibliothek wird in jitpack gehostet, also müssen Sie jitpack als Maven-Url unter dem Abschluss "All Projects" in Ihrer build.gradle auf Projektebene registrieren:

 maven { url "https://jitpack.io" }

Dann fügen Sie die Abhängigkeit in der app-level build.gradle hinzu:

implementation 'com.github.tiagohm:CodeView:0.4.0'

Jetzt synchronisieren, um die Bibliothek herunterzuladen und zu installieren.

Schritt 2: CodeView zum Layout hinzufügen

Gehen Sie zu dem xml-Layout, in dem Sie den Codeview rendern wollen und fügen Sie folgendes hinzu:

<br.tiagohm.codeview.CodeView
        android:id="@+id/codeView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:cv_font_size="14"
        app:cv_highlight_line_number="36"
        app:cv_show_line_number="true"
        app:cv_start_line_number="0"
        app:cv_wrap_line="true"
        app:cv_zoom_enable="true">
    </br.tiagohm.codeview.CodeView>

Schritt 3: Code schreiben

Schreiben Sie nun den Code. Wenn Sie Java verwenden, können Sie zum Beispiel den Codeview wie folgt referenzieren;

mCodeView = (CodeView)findViewById(R.id.codeView);

Oder Sie können Data Binding oder View Binding verwenden, egal ob Sie Java oder Kotlin verwenden. Sie können auch Kotlin-Synthetik verwenden, wenn Sie Kotlin verwenden.

Dann setzen Sie den Highlight-Listener, das Thema, den Code, die Sprache und andere Einstellungen wie Schriftgröße und Zoom-Eigenschaften wie folgt:

mCodeView.setOnHighlightListener(this)
      .setOnHighlightListener(this)
      .setTheme(Theme.AGATE)
      .setCode(JAVA_CODE)
      .setLanguage(Language.JAVA)
      .setWrapLine(true)
      .setFontSize(14)
      .setZoomEnabled(true)
      .setShowLineNumber(true)
      .setStartLineNumber(9000)
      .apply();

Hier sind einige andere Methoden:

mCodeView.highlightLineNumber(10);
mCodeView.toggleLineNumber();
mCodeView.getLineCount();

Beispiel

Schauen wir uns nun ein vollständiges Codeview-Beispiel an:

(a). activity_main.xml

Erstellen Sie das Layout für unsere Hauptaktivität und den Codeview dazu:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="br.tiagohm.codeview.app.MainActivity">

    <br.tiagohm.codeview.CodeView
        android:id="@+id/code_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        app:cv_font_size="14"
        app:cv_highlight_line_number="36"
        app:cv_show_line_number="true"
        app:cv_start_line_number="0"
        app:cv_wrap_line="true"
        app:cv_zoom_enable="true">
    </br.tiagohm.codeview.CodeView>

</LinearLayout>

(b). MainActivity.java

Unsere einzige Aktivität:

package br.tiagohm.codeview.app;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import br.tiagohm.codeview.CodeView;
import br.tiagohm.codeview.Language;
import br.tiagohm.codeview.Theme;

public class MainActivity extends AppCompatActivity implements CodeView.OnHighlightListener {

    private static final String JAVA_CODE = "package com.example.android.bluetoothchat;\n" +
            "\n" +
            "import android.os.Bundle;\n" +
            "import android.support.v4.app.FragmentTransaction;\n" +
            "import android.view.Menu;\n" +
            "import android.view.MenuItem;\n" +
            "import android.widget.ViewAnimator;\n" +
            "\n" +
            "import com.example.android.common.activities.SampleActivityBase;\n" +
            "import com.example.android.common.logger.Log;\n" +
            "import com.example.android.common.logger.LogFragment;\n" +
            "import com.example.android.common.logger.LogWrapper;\n" +
            "import com.example.android.common.logger.MessageOnlyLogFilter;\n" +
            "\n" +
            "/**\n" +
            " * A simple launcher activity containing a summary sample description, sample log and a custom\n" +
            " * {@link android.support.v4.app.Fragment} which can display a view.\n" +
            " * <p>\n" +
            " * For devices with displays with a width of 720dp or greater, the sample log is always visible,\n" +
            " * on other devices it's visibility is controlled by an item on the Action Bar.\n" +
            " */\n" +
            "public class MainActivity extends SampleActivityBase {\n" +
            "\n" +
            "    public static final String TAG = \"MainActivity\";\n" +
            "\n" +
            "    // Whether the Log Fragment is currently shown\n" +
            "    private boolean mLogShown;\n" +
            "\n" +
            "    @Override\n" +
            "    protected void onCreate(Bundle savedInstanceState) {\n" +
            "        super.onCreate(savedInstanceState);\n" +
            "        setContentView(R.layout.activity_main);\n" +
            "\n" +
            "        if (savedInstanceState == null) {\n" +
            "            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n" +
            "            BluetoothChatFragment fragment = new BluetoothChatFragment();\n" +
            "            transaction.replace(R.id.sample_content_fragment, fragment);\n" +
            "            transaction.commit();\n" +
            "        }\n" +
            "    }\n" +
            "\n" +
            "    @Override\n" +
            "    public boolean onCreateOptionsMenu(Menu menu) {\n" +
            "        getMenuInflater().inflate(R.menu.main, menu);\n" +
            "        return true;\n" +
            "    }\n" +
            "\n" +
            "    @Override\n" +
            "    public boolean onPrepareOptionsMenu(Menu menu) {\n" +
            "        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);\n" +
            "        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);\n" +
            "        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);\n" +
            "\n" +
            "        return super.onPrepareOptionsMenu(menu);\n" +
            "    }\n" +
            "\n" +
            "    @Override\n" +
            "    public boolean onPrepareOptionsMenu(Menu menu) {\n" +
            "        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);\n" +
            "        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);\n" +
            "        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);\n" +
            "\n" +
            "        return super.onPrepareOptionsMenu(menu);\n" +
            "    }\n" +
            "\n" +
            "    @Override\n" +
            "    public boolean onPrepareOptionsMenu(Menu menu) {\n" +
            "        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);\n" +
            "        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);\n" +
            "        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);\n" +
            "\n" +
            "        return super.onPrepareOptionsMenu(menu);\n" +
            "    }\n" +
            "\n" +
            "    @Override\n" +
            "    public boolean onOptionsItemSelected(MenuItem item) {\n" +
            "        switch(item.getItemId()) {\n" +
            "            case R.id.menu_toggle_log:\n" +
            "                mLogShown = !mLogShown;\n" +
            "                ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);\n" +
            "                if (mLogShown) {\n" +
            "                    output.setDisplayedChild(1);\n" +
            "                } else {\n" +
            "                    output.setDisplayedChild(0);\n" +
            "                }\n" +
            "                supportInvalidateOptionsMenu();\n" +
            "                return true;\n" +
            "        }\n" +
            "        return super.onOptionsItemSelected(item);\n" +
            "    }\n" +
            "\n" +
            "    /** Create a chain of targets that will receive log data */\n" +
            "    @Override\n" +
            "    public void initializeLogging() {\n" +
            "        // Wraps Android's native log framework.\n" +
            "        LogWrapper logWrapper = new LogWrapper();\n" +
            "        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.\n" +
            "        Log.setLogNode(logWrapper);\n" +
            "\n" +
            "        // Filter strips out everything except the message text.\n" +
            "        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();\n" +
            "        logWrapper.setNext(msgFilter);\n" +
            "\n" +
            "        // On screen logging via a fragment with a TextView.\n" +
            "        LogFragment logFragment = (LogFragment) getSupportFragmentManager()\n" +
            "                .findFragmentById(R.id.log_fragment);\n" +
            "        msgFilter.setNext(logFragment.getLogView());\n" +
            "\n" +
            "        Log.i(TAG, \"Ready\");\n" +
            "    }\n" +
            "}";

    CodeView mCodeView;
    private ProgressDialog mProgressDialog;
    private int themePos = 0;

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

        mCodeView = (CodeView) findViewById(R.id.code_view);

        mCodeView.setOnHighlightListener(this)
                .setOnHighlightListener(this)
                .setTheme(Theme.ARDUINO_LIGHT)
                .setCode(JAVA_CODE)
                .setLanguage(Language.AUTO)
                .setWrapLine(true)
                .setFontSize(14)
                .setZoomEnabled(true)
                .setShowLineNumber(true)
                .setStartLineNumber(1)
                .apply();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.change_theme_action:
                setHighlightTheme(++themePos);
                return true;
            case R.id.show_line_number_action:
                mCodeView.toggleLineNumber();
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onStartCodeHighlight() {
        mProgressDialog = ProgressDialog.show(this, null, "Carregando...", true);
    }

    @Override
    public void onFinishCodeHighlight() {
        if (mProgressDialog != null) {
            mProgressDialog.dismiss();
        }
        Toast.makeText(this, "line count: " + mCodeView.getLineCount(), Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onLanguageDetected(Language language, int relevance) {
        Toast.makeText(this, "language: " + language + " relevance: " + relevance, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onFontSizeChanged(int sizeInPx) {
        Log.d("TAG", "font-size: " + sizeInPx + "px");
    }

    @Override
    public void onLineClicked(int lineNumber, String content) {
        Toast.makeText(this, "line: " + lineNumber + " html: " + content, Toast.LENGTH_SHORT).show();
    }

    private void setHighlightTheme(int pos) {
        mCodeView.setTheme(Theme.ALL.get(pos)).apply();
        Toast.makeText(this, Theme.ALL.get(pos).getName(), Toast.LENGTH_SHORT).show();
    }
}

Quellcode finden Sie hier.

Referenz

Quellcode-Referenz finden hier.

(b). CodeView-Android

Zeigt Code mit Syntaxhervorhebung in nativer Weise an.

CodeView enthält 3 Kernteile, um die notwendige Logik zu implementieren:

  1. CodeView & zugehöriger abstrakter Adapter zur Bereitstellung von Optionen und Anpassungen (siehe unten).
  2. Für die Hervorhebung verwendet es CodeHighlighter, es hebt Ihren Code hervor und gibt formatierte Inhalte zurück. Es basiert auf Google Prettify und deren Java-Implementierung & fork.
  3. CodeClassifier versucht zu definieren, welche Sprache im Codeschnipsel dargestellt wird. Er basiert auf dem Naive Bayes Classifier, der auf einer Open-Source-Implementierung basiert, die ich in Kotlin umgeschrieben habe. Es ist nicht notwendig, direkt mit dieser Klasse zu arbeiten und Sie müssen nur den Anweisungen unten folgen. (Experimentelles Modul, kann nicht richtig funktionieren!)

Android CodeView Example

Schritt 1: Installieren

Diese Bibliothek wird auch in jitpack gehostet, also fügen Sie jitpack in Ihrer root level gradle Datei hinzu:

 maven { url "https://jitpack.io" }

Dann installieren Sie sie:

implementation 'com.github.kbiakov:CodeView-Android:1.3.2'

Schritt 2: CodeView Layout hinzufügen

Fügen Sie Codeview zu Ihrem xml-Layout hinzu:

<io.github.kbiakov.codeview.CodeView
    android:id="@+id/code_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

Schritt 3: Code schreiben

Tranin Code Classifier

Wenn Sie den Code Classifier zur automatischen Erkennung der Sprache verwenden möchten, fügen Sie ihn einfach in Ihre Application.java ein:

// train classifier on app start
CodeProcessor.init(this);

Reference CodeView

Das heißt, wenn Sie noch den alten findViewById Stil verwenden:

CodeView codeView = (CodeView) findViewById(R.id.code_view);

Set Code

Sie können jetzt Code auf Ihre Codeview mit automatischer Spracherkennung setzen:

// auto language recognition
codeView.setCode(getString(R.string.listing_js));

Sie können die Sprache auch explizit angeben:

// will work faster!
codeView.setCode(getString(R.string.listing_py), "py");

Thema ändern

Sie können das Theme wie folgt ändern:

codeView.getOptions().setTheme(ColorTheme.SOLARIZED_LIGHT);

Weitere Anpassungen:

codeView.setOptions(Options.Default.get(this)
    .withLanguage("python")
    .withCode(R.string.listing_py)
    .withTheme(ColorTheme.MONOKAI));

Und .

ColorThemeData myTheme = ColorTheme.SOLARIZED_LIGHT.theme()
    .withBgContent(android.R.color.black)
    .withNoteColor(android.R.color.white);

codeView.getOptions().setTheme(myTheme);

Schriftart einstellen

Sie können Ihre eigene Schriftart einstellen:

codeView.getOptions().withFont(Font.Consolas);

Beispiel

Ein komplettes Beispiel finden Sie hier

Referenz

Weitere Dokumentation finden Sie hier

Categorized in:

Tagged in: