PdfViewerFragment, Android uygulamanızda PDF dokümanlarını görüntülemek için kullanabileceğiniz özel bir Fragment'dir.
PdfViewerFragment, PDF oluşturmayı basitleştirerek uygulamanızın işlevselliğinin diğer yönlerine odaklanmanızı sağlar.
Sonuçlar
Sürüm uyumluluğu
PdfViewerFragment'yı kullanmak için uygulamanızın minimum Android S (API düzeyi 31) ve SDK uzantı düzeyi 13'ü hedeflemesi gerekir. Bu uyumluluk koşulları karşılanmazsa kitaplık UnsupportedOperationException oluşturur.
SdkExtensions modülünü kullanarak SDK uzantı sürümünü çalışma zamanında kontrol edebilirsiniz. Bu sayede, cihaz gerekli koşulları karşılıyorsa yalnızca koşullu olarak parçayı ve PDF belgesini yükleyebilirsiniz.
if (SdkExtensions.getExtensionVersion(Build.VERSION_CODES.S) >= 13) {
// Load the fragment and document.
}
Bağımlılıklar
PDF görüntüleyiciyi uygulamanıza dahil etmek için uygulamanızın modül build.gradle dosyasında androidx.pdf bağımlılığını bildirin. PDF kitaplığına Google Maven deposundan erişilebilir.
dependencies {
val pdfVersion = "1.0.0-alpha0X"
implementation("androidx.pdf:pdf:pdf-viewer-fragment:$pdfVersion")
}
PdfViewerFragment özellik
PdfViewerFragment, PDF belgelerini sayfalandırılmış biçimde sunarak gezinmeyi kolaylaştırır. Parçacık, verimli yükleme için sayfa boyutlarını aşamalı olarak yükleyen iki geçişli bir oluşturma stratejisi kullanır.
PdfViewerFragment, bellek kullanımını optimize etmek için yalnızca şu anda görünür olan sayfaları oluşturur ve ekran dışında kalan sayfaların bit eşlemlerini serbest bırakır.
Ayrıca, PdfViewerFragment, doküman URI'sini içeren örtülü bir android.intent.action.ANNOTATE amaçını tetikleyerek ek açıklamaları destekleyen bir kayan işlem düğmesi (FAB) içerir.
Uygulama
Android uygulamanıza PDF görüntüleyici eklemek çok adımlı bir işlemdir.
Etkinlik düzenini oluşturma
PDF görüntüleyiciyi barındıran etkinliğin düzen XML'sini tanımlayarak başlayın. Düzen, PdfViewerFragment ve kullanıcı etkileşimleri için düğmeleri (ör. belge içinde arama) içeren bir FrameLayout içermelidir.
<androidx.constraintlayout.widget.ConstraintLayout
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/pdf_container_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/fragment_container_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/search_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/search_string"
app:strokeWidth="1dp"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Etkinliği ayarlama
PdfViewerFragment öğesini barındıran etkinlik, AppCompatActivity öğesini genişletmelidir. Etkinliğin onCreate() yönteminde, içerik görünümünü oluşturduğunuz düzene ayarlayın ve gerekli tüm kullanıcı arayüzü öğelerini başlatın.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val getContentButton: MaterialButton = findViewById(R.id.launch_button)
val searchButton: MaterialButton = findViewById(R.id.search_button)
}
}
PdfViewerFragment başlatılıyor
getSupportFragmentManager() öğesinden alınan bir parça yöneticisini kullanarak PdfViewerFragment örneği oluşturun. Yeni bir parça oluşturmadan önce, özellikle yapılandırma değişiklikleri sırasında, parçanın bir örneğinin zaten mevcut olup olmadığını kontrol edin.
Aşağıdaki örnekte, initializePdfViewerFragment() işlevi parça işleminin oluşturulmasını ve işlenmesini sağlar. Bu işlev, kapsayıcıdaki mevcut bir parçayı PdfViewerFragment örneğinizle değiştirir.
class MainActivity : AppCompatActivity() {
@RequiresExtension(extension = Build.VERSION_CODES.S, version = 13)
private var pdfViewerFragment: PdfViewerFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
// ...
if (pdfViewerFragment == null) {
pdfViewerFragment =
supportFragmentManager
.findFragmentByTag(PDF_VIEWER_FRAGMENT_TAG) as PdfViewerFragment?
}
}
// Used to instantiate and commit the fragment.
@RequiresExtension(extension = Build.VERSION_CODES.S, version = 13)
private fun initializePdfViewerFragment() {
// This condition can be skipped if you want to create a new fragment every time.
if (pdfViewerFragment == null) {
val fragmentManager: FragmentManager = supportFragmentManager
// Fragment initialization.
pdfViewerFragment = PdfViewerFragmentExtended()
val transaction: FragmentTransaction = fragmentManager.beginTransaction()
// Replace an existing fragment in a container with an instance of a new fragment.
transaction.replace(
R.id.fragment,4_container_view,
pdfViewerFragment!!,
PDF_VIEWER_FRAGMENT_TAG
)
transaction.commitAllowingStateLoss()
fragmentManager.executePendingTransactions()
}
}
companion object {
private const val MIME_TYPE_PDF = "application/pdf"
private const val PDF_VIEWER_FRAGMENT_TAG = "pdf_viewer_fragment_tag"
}
}
PdfViewerFragment işlevini genişletme
PdfViewerFragment, özelliklerini genişletmek için geçersiz kılınabilecek herkese açık işlevleri kullanıma sunar. PdfViewerFragment'dan devralan yeni bir sınıf oluşturun. Alt sınıfınızda, metrikleri kaydetme gibi özel mantık eklemek için onLoadDocumentSuccess() ve onLoadDocumentError() gibi yöntemleri geçersiz kılın.
@RequiresExtension(extension = Build.VERSION_CODES.S, version = 13)
class PdfViewerFragmentExtended : PdfViewerFragment() {
private val someLogger : SomeLogger = // ... used to log metrics
override fun onLoadDocumentSuccess() {
someLogger.log(/** log document success */)
}
override fun onLoadDocumentError(error: Throwable) {
someLogger.log(/** log document error */, error)
}
}
Doküman arama özelliğini etkinleştirme
PdfViewerFragment, yerleşik bir arama menüsü içermese de arama çubuğunu destekler. isTextSearchActive API'sini kullanarak arama çubuğunun görünürlüğünü kontrol edebilirsiniz. Doküman aramasını etkinleştirmek için PdfViewerFragment örneğinizin isTextSearchActive özelliğini ayarlarsınız.
Arama görünümünün doğru konumlandırılması için gerekli olan WindowInsetsCompat değerinin içerik görünümlerine doğru şekilde iletildiğinden emin olmak için WindowCompat.setDecorFitsSystemWindows() kullanın.
class MainActivity : AppCompatActivity() {
@RequiresExtension(extension = Build.VERSION_CODES.S, version = 13)
override fun onCreate(savedInstanceState: Bundle?) {
// ...
searchButton.setOnClickListener {
pdfViewerFragment?.isTextSearchActive =
pdfViewerFragment?.isTextSearchActive == false
}
// Ensure WindowInsetsCompat are passed to content views without being
// consumed by the decor view. These insets are used to calculate the
// position of the search view.
WindowCompat.setDecorFitsSystemWindows(window, false)
}
}
Dosya seçiciyle entegrasyon
Kullanıcıların cihazlarından PDF dosyaları seçmesine izin vermek için PdfViewerFragment'yı Android dosya seçiciyle entegre edin. Öncelikle, dosya seçiciyi başlatan bir düğme eklemek için etkinliğinizin düzen XML'sini güncelleyin.
<androidx.constraintlayout.widget.ConstraintLayout
...
tools:context=".MainActivity">
<FrameLayout
...
app:layout_constraintBottom_toTopOf="@+id/launch_button"/>
// Adding a button to open file picker.
<com.google.android.material.button.MaterialButton
android:id="@+id/launch_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/launch_string"
app:strokeWidth="1dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/search_button"/>
<com.google.android.material.button.MaterialButton
...
app:layout_constraintStart_toEndOf="@id/launch_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
Ardından, etkinliğinizde registerForActivityResult(GetContent()) kullanarak dosya seçiciyi başlatın. Kullanıcı bir dosya seçtiğinde geri çağırma, URI sağlar. Ardından, seçilen PDF'yi yüklemek ve görüntülemek için PdfViewerFragment örneğinizin documentUri özelliğini bu URI ile ayarlarsınız.
class MainActivity : AppCompatActivity() {
// ...
private var filePicker: ActivityResultLauncher<String> =
registerForActivityResult(GetContent()) { uri: Uri? ->
uri?.let {
initializePdfViewerFragment()
pdfViewerFragment?.documentUri = uri
}
}
override fun onCreate(savedInstanceState: Bundle?) {
// ...
getContentButton.setOnClickListener { filePicker.launch(MIME_TYPE_PDF) }
}
private fun initializePdfViewerFragment() {
// ...
}
companion object {
private const val MIME_TYPE_PDF = "application/pdf"
// ...
}
}
Kullanıcı arayüzünü özelleştirme
Kitaplığın sunduğu XML özelliklerini geçersiz kılarak PdfViewerFragment kullanıcı arayüzünü özelleştirebilirsiniz. Bu sayede, kaydırma çubuğu ve sayfa göstergesi gibi öğelerin görünümünü uygulamanızın tasarımına uyacak şekilde özelleştirebilirsiniz.
Özelleştirilebilir özellikler şunlardır:
fastScrollVerticalThumbDrawable: Kaydırma çubuğu başparmağı için çizilebilir öğeyi ayarlar.fastScrollPageIndicatorBackgroundDrawable— Sayfa göstergesi için arka plan çizilebilir öğesini ayarlar.fastScrollPageIndicatorMarginEnd: Sayfa göstergesi için sağ kenar boşluğunu ayarlar. Marj değerlerinin pozitif olduğundan emin olun.fastScrollVerticalThumbMarginEnd: Dikey kaydırma çubuğu başparmağı için sağ kenar boşluğunu ayarlar. Marj değerlerinin pozitif olduğundan emin olun.
Bu özelleştirmeleri uygulamak için XML kaynaklarınızda özel bir stil tanımlayın.
<resources>
<style name="pdfContainerStyle">
<item name="fastScrollVerticalThumbDrawable">@drawable/custom_thumb_drawable</item>
<item name="fastScrollPageIndicatorBackgroundDrawable">@drawable/custom_page_indicator_background</item>
<item name="fastScrollVerticalThumbMarginEnd">8dp</item>
</style>
</resources>
Ardından, PdfViewerFragment kullanarak özel stil kaynağını PdfStylingOptions öğesine sağlayın. Bunu, PdfViewerFragment.newInstance(stylingOptions) ile parçanın bir örneğini oluştururken yaparsınız.
private fun initializePdfViewerFragment() {
// This condition can be skipped if you want to create a new fragment every time.
if (pdfViewerFragment == null) {
val fragmentManager: FragmentManager = supportFragmentManager
// Create styling options.
val stylingOptions = PdfStylingOptions(R.style.pdfContainerStyle)
// Fragment initialization.
pdfViewerFragment = PdfViewerFragment.newInstance(stylingOptions)
// Execute fragment transaction.
}
}
PdfViewerFragment sınıfını alt sınıfa ayırdıysanız stil seçeneklerini sağlamak için protected oluşturucuyu kullanın. Bu, özel stillerinizin genişletilmiş parçanıza doğru şekilde uygulanmasını sağlar.
class StyledPdfViewerFragment: PdfViewerFragment {
constructor() : super()
private constructor(pdfStylingOptions: PdfStylingOptions) : super(pdfStylingOptions)
companion object {
fun newInstance(): StyledPdfViewerFragment {
val stylingOptions = PdfStylingOptions(R.style.pdfContainerStyle)
return StyledPdfViewerFragment(stylingOptions)
}
}
}
Uygulamayı tamamlama
Aşağıdaki kod, başlatma, dosya seçici entegrasyonu, arama işlevi ve kullanıcı arayüzü özelleştirme dahil olmak üzere PdfViewerFragment öğesini etkinliğinizde nasıl uygulayacağınızla ilgili eksiksiz bir örnek sunar.
class MainActivity : AppCompatActivity() {
private var pdfViewerFragment: PdfViewerFragment? = null
private var filePicker: ActivityResultLauncher<String> =
registerForActivityResult(GetContent()) { uri: Uri? ->
uri?.let {
initializePdfViewerFragment()
pdfViewerFragment?.documentUri = uri
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (pdfViewerFragment == null) {
pdfViewerFragment =
supportFragmentManager
.findFragmentByTag(PDF_VIEWER_FRAGMENT_TAG) as PdfViewerFragment?
}
val getContentButton: MaterialButton = findViewById(R.id.launch_button)
val searchButton: MaterialButton = findViewById(R.id.search_button)
getContentButton.setOnClickListener { filePicker.launch(MIME_TYPE_PDF) }
searchButton.setOnClickListener {
pdfViewerFragment?.isTextSearchActive = pdfViewerFragment?.isTextSearchActive == false
}
}
private fun initializePdfViewerFragment() {
// This condition can be skipped if you want to create a new fragment every time.
if (pdfViewerFragment == null) {
val fragmentManager: FragmentManager = supportFragmentManager
// Create styling options.
// val stylingOptions = PdfStylingOptions(R.style.pdfContainerStyle)
// Fragment initialization.
// For customization:
// pdfViewerFragment = PdfViewerFragment.newInstance(stylingOptions)
pdfViewerFragment = PdfViewerFragmentExtended()
val transaction: FragmentTransaction = fragmentManager.beginTransaction()
// Replace an existing fragment in a container with an instance of a new fragment.
transaction.replace(
R.id.fragment_container_view,
pdfViewerFragment!!,
PDF_VIEWER_FRAGMENT_TAG
)
transaction.commitAllowingStateLoss()
fragmentManager.executePendingTransactions()
}
}
companion object {
private const val MIME_TYPE_PDF = "application/pdf"
private const val PDF_VIEWER_FRAGMENT_TAG = "pdf_viewer_fragment_tag"
}
}
Kodla ilgili önemli noktalar
- Projenizin minimum API düzeyi ve SDK uzantısı şartlarını karşıladığından emin olun.
PdfViewerFragmentöğesini barındıran etkinlik,AppCompatActivityöğesini genişletmelidir.- Özel davranışlar eklemek için
PdfViewerFragmentöğesini genişletebilirsiniz. - XML özelliklerini geçersiz kılarak
PdfViewerFragmentkullanıcı arayüzünü özelleştirin.