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 özelliğini kullanmak için uygulamanızın en az 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.
SDK uzantısı sürümünü çalışma zamanında SdkExtensions
modülünü kullanarak 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ı beyan edin. 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ça, verimli yükleme için sayfa boyutlarını kademeli 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 amacı 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 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şlevler sunar. PdfViewerFragment öğesinden 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. Arama çubuğunun görünürlüğünü isTextSearchActive API'siyle kontrol edersiniz. 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 öğesinin 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.
<...>
<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ştirilebilen ö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ı sağlayın. PdfStylingOptions ile parçanın bir örneğini oluşturduğunuzda PdfViewerFragment.newInstance(stylingOptions) kullanın.
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.
- Etkinliğe ev sahipliği yapan
PdfViewerFragment,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.