Si vous créez une application de tutoriel ou une sorte d'application qui enseigne le codage, alors vous auriez besoin d'un widget natif capable non seulement de rendre le code mais aussi de l'éclairer. Un tel widget est ce que nous appelons codeview et c'est ce que nous couvrons dans ce tutoriel. Nous examinons plusieurs bibliothèques et exemples de codeview.

(a). CodeView

widget de mise en évidence du code.

Voici les caractéristiques de ce widget :

  • Powered by Highlight.js
  • 176 langues et 79 styles
  • Ligne d'enveloppement
  • Détection de la langue
  • Zoom (geste de pincement)
  • Numéro de ligne
  • Nombre de lignes
  • Mise en évidence de la ligne en cours (par clic/tap)
  • Mise en évidence de la ligne
  • Événement de tapotement des lignes (obtenir le numéro de ligne et votre contenu)

Voici une démo simple :

Etape 1 : Installer CodeView

Cette bibliothèque est hébergée dans jitpack donc vous devez enregistrer jitpack comme une url maven sous la fermeture all projects dans votre build.gradle au niveau du projet :

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

Puis ajouter la dépendance dans le build.gradle au niveau de l'application :

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

Maintenant synchro pour télécharger et installer la bibliothèque.

Etape 2 : Ajouter le CodeView au Layout

Allez dans le layout xml où vous voulez rendre le codeview puis ajoutez ce qui suit :

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

Étape 3 : Écrire le code

Maintenant, allez-y et écrivez du code. Si vous utilisez java, vous pouvez par exemple référencer le codeview comme suit ;

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

Ou vous pouvez utiliser le data binding ou le view binding que vous utilisiez java ou kotlin. Vous pouvez également utiliser les synthèses kotlin si vous utilisez kotlin.

Ensuite, définissez l'écouteur de mise en évidence, le thème, le code, la langue et d'autres paramètres comme la taille de la police et les propriétés de zoom comme suit :

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

Voici d'autres méthodes :

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

Exemple

Regardons maintenant un exemple de codeview complet :

(a). activité_main.xml

Créez la mise en page de notre activité principale et codeview à elle :

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

Notre seule activité :

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

Trouvez le code source ici.

Référence

Trouver la référence du code source ici.

(b). CodeView-Android

Affichez le code avec la coloration syntaxique en mode natif.

CodeView contient 3 parties principales pour implémenter la logique nécessaire :

  1. CodeView et adaptateur abstrait connexe pour fournir des options et la personnalisation (voir ci-dessous).
  2. Pour la mise en évidence, il utilise CodeHighlighter, il met en évidence votre code et renvoie un contenu formaté. Il est basé sur Google Prettify et leur implémentation Java & fork.
  3. CodeClassifier essaie de définir quel langage est présenté dans l'extrait de code. Il est construit à l'aide du Naive Bayes classifier sur la base de l'implémentation open-source, que j'ai réécrite en Kotlin. Il n'y a pas besoin de travailler directement avec cette classe et vous devez juste suivre les instructions ci-dessous. (Module expérimental, peut ne pas fonctionner correctement !)

Android CodeView Example

Etape 1 : L'installer

Cette bibliothèque est également hébergée dans jitpack donc vous ajoutez jitpack dans votre fichier gradle de niveau racine :

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

Puis l'installer :

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

Étape 2 : Ajouter la mise en page CodeView

Ajoutez codeview à votre mise en page xml :

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

Step 3 : Write Code

Tranin Code Classifier

Si vous voulez utiliser le classificateur de code pour la reconnaissance automatique de la langue, ajoutez simplement à votre Application.java :

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

Reference CodeView

C'est-à-dire si vous utilisez toujours l'ancien style findViewById :

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

Set Code

Vous pouvez maintenant définir le code sur votre codeview avec la détection automatique de la langue :

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

Vous pouvez également spécifier explicitement la langue :

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

Changer de thème

Vous pouvez changer de thème comme suit :

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

Plus de personnalisations :

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

Et

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

codeView.getOptions().setTheme(myTheme);

Définition de la police

Vous pouvez définir votre propre police de caractères :

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

Exemple

Trouvez un exemple complet ici

Référence

Trouvez plus de documentation ici

Catégorisé: