效果图:
上图附件下的fragment内显示的就是pdf
兼容android 8.0,直接获取服务端返的url(http.....pdf)直接打开。
在assets文件下,粘贴过去pdfjs的整个包。(在文章尾部提供)
权限为了简便,我就直接粘贴了常用的。大家自行合理删减
在application的地方设置属性,红线标识的位置。
同时,安卓6.0以后的 动态配置权限也要执行。
大家根据自己的包名去更改。
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
android:id="@+id/view_web"
android:layout_width="match_parent"
android:layout_height="match_parent" />
很简单的放个自定义的webView,采用自定义的是因为这个界面在viewpager中滑动冲突
package com.yc.stscf.widget; import android.annotation.SuppressLint; import android.content.Context; import android.support.v4.view.MotionEventCompat; import android.util.AttributeSet; import android.view.MotionEvent; import android.webkit.WebView; /** * ================================================ * * @author :Vip * @version :V 1.0.0 * @date :2019/7/24 16:51 * 描 述:主要解决viewPager嵌套webView横向滚动问题 * 修订历史: * ================================================ */ public class ExtendedWebView extends WebView { private boolean isScrollX = false; public ExtendedWebView(Context context) { super(context); } public ExtendedWebView(Context context, AttributeSet attrs) { super(context, attrs); } @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouchEvent(MotionEvent event) { if (MotionEventCompat.getPointerCount(event) == 1) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isScrollX = false; //事件由webView处理 getParent().getParent() .requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_MOVE: //嵌套Viewpager时 getParent().getParent() .requestDisallowInterceptTouchEvent(!isScrollX); break; default: getParent().getParent() .requestDisallowInterceptTouchEvent(false); } } else { //使webView可以双指缩放(前提是webView必须开启缩放功能,并且加载的网页也支持缩放) getParent().getParent(). requestDisallowInterceptTouchEvent(true); } return super.onTouchEvent(event); } /** * 当webView滚动到边界时执行 **/ @Override protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { super.onOverScrolled(scrollX, scrollY, clampedX, clampedY); isScrollX = clampedX; } }
package com.yc.stscf.fragment.contract; import android.annotation.SuppressLint; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import com.yc.stscf.R; import com.yc.stscf.base.BaseFragment; import com.yc.stscf.widget.ExtendedWebView; import butterknife.BindView; /** * ================================================ * * @author :Vip * @version :V 1.0.0 * @date :2019/7/9 15:47 * 描 述:pdf展示 * 修订历史: * ================================================ */ public class ContractEnclosureFragment extends BaseFragment { @BindView(R.id.view_web) ExtendedWebView pdfShowWebView; /** * 总布局 **/ private View view = null; /** * 标志位,标志已经初始化完成 **/ private boolean isPrepared; @SuppressLint("InflateParams") @Override protected View initLayout(LayoutInflater inflater, ViewGroup container, boolean b) { view = inflater.inflate(R.layout.fragment_contract_enclosure, null); isPrepared = true; return view; } @SuppressLint("SetJavaScriptEnabled") @Override protected void initView(Bundle savedInstanceState) { pdfShowWebView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // 返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器 view.loadUrl(url); return true; } }); WebSettings settings = pdfShowWebView.getSettings(); settings.setSavePassword(false); settings.setJavaScriptEnabled(true); settings.setAllowFileAccessFromFileURLs(true); settings.setAllowUniversalAccessFromFileURLs(true); settings.setBuiltInZoomControls(true); pdfShowWebView.requestDisallowInterceptTouchEvent(true); String mPdfFilePath = "http://114.115.152.132:80/lessonDoc/1540185667975.pdf"; pdfShowWebView.setWebChromeClient(new WebChromeClient()); // if (!"".equals(mPdfFilePath)) { // byte[] bytes = null; // try {// 获取以字符编码为utf-8的字符 // bytes = mPdfFilePath.getBytes("UTF-8"); // } catch (UnsupportedEncodingException e) { // e.printStackTrace(); // } // if (bytes != null) { // // BASE64转码 // mPdfFilePath = new Base64Encoder().encode(bytes); // } // } //TODO 采用无样式的,则引用index.html?不需要file=,并且mPdfFilePath不需要转码。 pdfShowWebView.loadUrl("file:///android_asset/pdfjs/web/index.html?" + mPdfFilePath); //TODO 采用有样式的,则引用 viewer.html?file=,需要mPdfFilePath转码 // pdfShowWebView.loadUrl("file:///android_asset/pdfjs/web/viewer.html?file=" + mPdfFilePath); } @Override protected void lazyLoad() { if (!isPrepared || !isVisible) { return; } } }
baseFragment是我自定义的,可以采用原始的fragment去继承。
采用了2种方式。在pdf的资源内已经继承完毕。分为1:全屏的仅仅显示pdf,2:pdf顶部带导航栏,放大缩小快速跳转定位,打印等。 建议方式一,方式一的样式更加美观。方式二是原生的,样式会丑些,当然也是可以修改的,需要掌握一定前端功底,改css样式。 在代码中已经描述了。方式二级(采用有样式的),将注释掉的放开、Base64Encoder是做转码用的,不适用的话加载不出来
package com.yc.stscf.utils; import java.io.IOException; import java.io.OutputStream; /** * ================================================ * * @author:Vip 版 本:V4.1.4 * 创建日期:2018/6/29 * 描 述:配合在线预览pdf * 修订历史: * ================================================ */ public class Base64Encoder extends CharacterEncoder { @Override protected int bytesPerAtom() { return 3; } @Override protected int bytesPerLine() { return 57; } private static final char[] PEM_ARRAY = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '='}; @Override protected void encodeAtom(OutputStream paramOutputStream, byte[] paramArrayOfByte, int paramInt1, int paramInt2) throws IOException { int i; int j; int k; if (paramInt2 == 1) { i = paramArrayOfByte[paramInt1]; j = 0; k = 0; paramOutputStream.write(PEM_ARRAY[(i >>> 2 & 0x3F)]); paramOutputStream .write(PEM_ARRAY[((i << 4 & 0x30) + (j >>> 4 & 0xF))]); paramOutputStream.write(61); paramOutputStream.write(61); } else if (paramInt2 == 2) { i = paramArrayOfByte[paramInt1]; j = paramArrayOfByte[(paramInt1 + 1)]; k = 0; paramOutputStream.write(PEM_ARRAY[(i >>> 2 & 0x3F)]); paramOutputStream .write(PEM_ARRAY[((i << 4 & 0x30) + (j >>> 4 & 0xF))]); paramOutputStream .write(PEM_ARRAY[((j << 2 & 0x3C) + (k >>> 6 & 0x3))]); paramOutputStream.write(61); } else { i = paramArrayOfByte[paramInt1]; j = paramArrayOfByte[(paramInt1 + 1)]; k = paramArrayOfByte[(paramInt1 + 2)]; paramOutputStream.write(PEM_ARRAY[(i >>> 2 & 0x3F)]); paramOutputStream .write(PEM_ARRAY[((i << 4 & 0x30) + (j >>> 4 & 0xF))]); paramOutputStream .write(PEM_ARRAY[((j << 2 & 0x3C) + (k >>> 6 & 0x3))]); paramOutputStream.write(PEM_ARRAY[(k & 0x3F)]); } } }
package com.yc.stscf.utils; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.nio.ByteBuffer; /** * ================================================ * * @author:Vip 版 本:V4.1.4 * 创建日期:2018/6/29 * 描 述:配合在线预览pdf * 修订历史: * ================================================ */ public abstract class CharacterEncoder { private PrintStream pStream; protected abstract int bytesPerAtom(); protected abstract int bytesPerLine(); private void encodeBufferPrefix(OutputStream paramOutputStream) throws IOException { this.pStream = new PrintStream(paramOutputStream); } private void encodeBufferSuffix(OutputStream paramOutputStream) throws IOException { } private void encodeLinePrefix(OutputStream paramOutputStream, int paramInt) throws IOException { } private void encodeLineSuffix(OutputStream paramOutputStream) throws IOException { this.pStream.println(); } protected abstract void encodeAtom(OutputStream paramOutputStream, byte[] paramArrayOfByte, int paramInt1, int paramInt2) throws IOException; private int readFully(InputStream paramInputStream, byte[] paramArrayOfByte) throws IOException { for (int i = 0; i < paramArrayOfByte.length; i++) { int j = paramInputStream.read(); if (j == -1) { return i; } paramArrayOfByte[i] = ((byte) j); } return paramArrayOfByte.length; } private void encode(InputStream paramInputStream, OutputStream paramOutputStream) throws IOException { byte[] arrayOfByte = new byte[bytesPerLine()]; encodeBufferPrefix(paramOutputStream); for (; ; ) { int j = readFully(paramInputStream, arrayOfByte); if (j == 0) { break; } encodeLinePrefix(paramOutputStream, j); for (int i = 0; i < j; i += bytesPerAtom()) { if (i + bytesPerAtom() <= j) { encodeAtom(paramOutputStream, arrayOfByte, i, bytesPerAtom()); } else { encodeAtom(paramOutputStream, arrayOfByte, i, j - i); } } if (j < bytesPerLine()) { break; } encodeLineSuffix(paramOutputStream); } encodeBufferSuffix(paramOutputStream); } private void encode(byte[] paramArrayOfByte, OutputStream paramOutputStream) throws IOException { ByteArrayInputStream localByteArrayInputStream = new ByteArrayInputStream(paramArrayOfByte); encode(localByteArrayInputStream, paramOutputStream); } public String encode(byte[] paramArrayOfByte) { ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream(); ByteArrayInputStream localByteArrayInputStream = new ByteArrayInputStream(paramArrayOfByte); String str = null; try { encode(localByteArrayInputStream, localByteArrayOutputStream); str = localByteArrayOutputStream.toString("8859_1"); } catch (Exception localException) { throw new Error("CharacterEncoder.encode internal error"); } return str; } private byte[] getBytes(ByteBuffer paramByteBuffer) { byte[] localObject = null; if (paramByteBuffer.hasArray()) { byte[] arrayOfByte = paramByteBuffer.array(); if ((arrayOfByte.length == paramByteBuffer.capacity()) && (arrayOfByte.length == paramByteBuffer.remaining())) { localObject = arrayOfByte; paramByteBuffer.position(paramByteBuffer.limit()); } } if (localObject == null) { localObject = new byte[paramByteBuffer.remaining()]; paramByteBuffer.get((byte[]) localObject); } return localObject; } public void encode(ByteBuffer paramByteBuffer, OutputStream paramOutputStream) throws IOException { byte[] arrayOfByte = getBytes(paramByteBuffer); encode(arrayOfByte, paramOutputStream); } public String encode(ByteBuffer paramByteBuffer) { byte[] arrayOfByte = getBytes(paramByteBuffer); return encode(arrayOfByte); } private void encodeBuffer(InputStream paramInputStream, OutputStream paramOutputStream) throws IOException { byte[] arrayOfByte = new byte[bytesPerLine()]; encodeBufferPrefix(paramOutputStream); for (; ; ) { int j = readFully(paramInputStream, arrayOfByte); if (j != 0) { encodeLinePrefix(paramOutputStream, j); for (int i = 0; i < j; i += bytesPerAtom()) { if (i + bytesPerAtom() <= j) { encodeAtom(paramOutputStream, arrayOfByte, i, bytesPerAtom()); } else { encodeAtom(paramOutputStream, arrayOfByte, i, j - i); } } encodeLineSuffix(paramOutputStream); if (j < bytesPerLine()) { break; } } } encodeBufferSuffix(paramOutputStream); } private void encodeBuffer(byte[] paramArrayOfByte, OutputStream paramOutputStream) throws IOException { ByteArrayInputStream localByteArrayInputStream = new ByteArrayInputStream(paramArrayOfByte); encodeBuffer(localByteArrayInputStream, paramOutputStream); } private String encodeBuffer(byte[] paramArrayOfByte) { ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream(); ByteArrayInputStream localByteArrayInputStream = new ByteArrayInputStream(paramArrayOfByte); try { encodeBuffer(localByteArrayInputStream, localByteArrayOutputStream); } catch (Exception localException) { throw new Error("CharacterEncoder.encodeBuffer internal error"); } return localByteArrayOutputStream.toString(); } public void encodeBuffer(ByteBuffer paramByteBuffer, OutputStream paramOutputStream) throws IOException { byte[] arrayOfByte = getBytes(paramByteBuffer); encodeBuffer(arrayOfByte, paramOutputStream); } public String encodeBuffer(ByteBuffer paramByteBuffer) { byte[] arrayOfByte = getBytes(paramByteBuffer); return encodeBuffer(arrayOfByte); } }
最后: pdf包的引用文件放在了我的下载内容里。大家去里面下载吧。我想免费提供。只是csdn不允许。而且默认设置了5积分。
下载地址:https://download.csdn.net/download/qq_35874340/11295568
https://download.csdn.net/download/qq_35874340/11381668