You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android新字体安装技术咨询:下拉选单选择TTF字体的代码指导

Got it, let's walk through how to build this font selection and installation feature step by step. I’ll assume you’re using Flutter since you mentioned an assets/font folder—if you’re working with another framework (like Android native or iOS), just let me know and I can adjust the code examples!

Step 1: Build the Font Selection Dropdown

First, let’s set up the dropdown with your font list. We’ll start by defining the list of font filenames (match what’s in your assets/font directory), then render a dropdown that lets users pick a font.

// Define your font list (update these to match your actual TTF files)
final List<String> fontList = [
  'Roboto-Regular.ttf',
  'OpenSans-Bold.ttf',
  'Montserrat-Italic.ttf'
];

String? selectedFont;

// Add this to your widget's build method
DropdownButton<String>(
  value: selectedFont,
  hint: const Text('Pick a font to install'),
  onChanged: (String? newFont) {
    setState(() {
      selectedFont = newFont;
      // Trigger installation as soon as a font is selected
      if (newFont != null) handleFontInstallation(newFont);
    });
  },
  items: fontList.map((String fontName) {
    return DropdownMenuItem<String>(
      value: fontName,
      // Show a clean name (without the .ttf extension) to users
      child: Text(fontName.replaceAll('.ttf', '')),
    );
  }).toList(),
)
Step 2: Implement Font Installation Logic

There are two main scenarios here: using the font only in your app, or installing it to the device’s system so other apps can use it too. Let’s cover both:

Option A: Load Font for App-Only Use (No System Installation)

If you just want the selected font to work within your app, you don’t need to install it system-wide. Use Flutter’s FontLoader to load the font on the fly:

Future<void> handleFontInstallation(String fontFileName) async {
  // Extract the font family name (remove .ttf)
  final fontFamilyName = fontFileName.replaceAll('.ttf', '');
  
  try {
    // Load the font from assets
    final fontLoader = FontLoader(fontFamilyName)
      ..addFont(rootBundle.load('assets/font/$fontFileName'))
      ..load();
    await fontLoader;
    
    // After loading, you can apply this font to your app's theme or specific widgets
    // Example: Update the app theme to use the new font
    setState(() {
      Theme.of(context).copyWith(
        textTheme: TextTheme(
          bodyLarge: TextStyle(fontFamily: fontFamilyName),
          titleLarge: TextStyle(fontFamily: fontFamilyName),
        ),
      );
    });
    
    // Show a success message to the user
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('$fontFamilyName loaded successfully!')),
    );
  } catch (e) {
    // Handle errors (e.g., file not found)
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Failed to load font: ${e.toString()}')),
    );
  }
}

Option B: Install Font to Device System

If you want the font to be available across the entire device (for other apps too), you’ll need to write native code for Android and iOS, then call it from Flutter using a MethodChannel.

First, Set Up the MethodChannel in Flutter

final MethodChannel _fontInstallChannel = MethodChannel('com.yourapp/font_installer');

Future<void> handleFontInstallation(String fontFileName) async {
  try {
    await _fontInstallChannel.invokeMethod(
      'installFont',
      {'fontFileName': fontFileName},
    );
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Font installed successfully!')),
    );
  } on PlatformException catch (e) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Installation failed: ${e.message}')),
    );
  }
}

Android Native Code (MainActivity.kt)

Add this to your Android MainActivity to handle copying the font to the system’s font directory and triggering a media scan:

import android.content.Intent
import android.net.Uri
import android.os.Environment
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import java.io.File
import java.io.FileOutputStream
import java.io.IOException

class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.yourapp/font_installer"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "installFont") {
                val fontFileName = call.argument<String>("fontFileName")
                if (fontFileName != null) {
                    try {
                        installFontToSystem(fontFileName)
                        result.success(null)
                    } catch (e: IOException) {
                        result.error("INSTALL_FAILED", e.message, null)
                    }
                } else {
                    result.error("INVALID_ARG", "Font filename is null", null)
                }
            } else {
                result.notImplemented()
            }
        }
    }

    @Throws(IOException::class)
    private fun installFontToSystem(fontFileName: String) {
        // Copy font from assets to external storage's font directory
        val inputStream = assets.open("font/$fontFileName")
        val fontDir = getExternalFilesDir(Environment.DIRECTORY_FONTS)
        val fontFile = File(fontDir, fontFileName)

        FileOutputStream(fontFile).use { outputStream ->
            val buffer = ByteArray(1024)
            var length: Int
            while (inputStream.read(buffer).also { length = it } > 0) {
                outputStream.write(buffer, 0, length)
            }
        }

        // Tell the system to scan the new font file
        val scanIntent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
        scanIntent.data = Uri.fromFile(fontFile)
        sendBroadcast(scanIntent)
    }
}

iOS Native Code (AppDelegate.swift)

Add this to your iOS AppDelegate to register the font with the system using CoreText:

import UIKit
import Flutter
import CoreText

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    private let CHANNEL = "com.yourapp/font_installer"

    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        let channel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger)
        
        channel.setMethodCallHandler { [weak self] call, result in
            guard call.method == "installFont" else {
                result.notImplemented()
                return
            }
            
            guard let args = call.arguments as? [String: String], let fontFileName = args["fontFileName"] else {
                result.error("INVALID_ARG", "Font filename is null", nil)
                return
            }
            
            self?.installFontToSystem(fontFileName) { success, error in
                if success {
                    result.success(nil)
                } else {
                    result.error("INSTALL_FAILED", error?.localizedDescription, nil)
                }
            }
        }

        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
    
    private func installFontToSystem(_ fontFileName: String, completion: @escaping (Bool, Error?) -> Void) {
        guard let fontPath = Bundle.main.path(forResource: "font/\(fontFileName)", ofType: nil) else {
            completion(false, NSError(domain: "FontNotFound", code: 0, userInfo: [NSLocalizedDescriptionKey: "Font file not found"]))
            return
        }
        
        let fontURL = URL(fileURLWithPath: fontPath)
        do {
            let fontData = try Data(contentsOf: fontURL)
            guard let provider = CGDataProvider(data: fontData as CFData) else {
                completion(false, NSError(domain: "FontLoadFailed", code: 1, userInfo: [NSLocalizedDescriptionKey: "Failed to create font provider"]))
                return
            }
            
            guard let font = CGFont(provider) else {
                completion(false, NSError(domain: "FontLoadFailed", code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to load font"]))
                return
            }
            
            var error: Unmanaged<CFError>?
            if CTFontManagerRegisterGraphicsFont(font, &error) {
                completion(true, nil)
            } else {
                completion(false, error?.takeRetainedValue())
            }
        } catch {
            completion(false, error)
        }
    }
}
Step 3: Don’t Forget to Update pubspec.yaml

Make sure your font assets are declared in pubspec.yaml so Flutter can access them:

flutter:
  assets:
    - assets/font/
Key Notes to Keep in Mind
  • Permissions: For Android versions older than 13, you’ll need to request the WRITE_EXTERNAL_STORAGE permission. On Android 13+, the DIRECTORY_FONTS is accessible without extra permissions.
  • Error Handling: Always catch exceptions (like missing files, permission denied) and show clear messages to users.
  • Testing: Test on real devices—emulators might behave differently when it comes to system font installation.

内容的提问来源于stack exchange,提问作者Tony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:21:15