【已解决】 加载本地小说第一页显示不出来。
在读取本地小说显示的时候,第一页总是显示阴影界面,从第二页会正常显示,从第二页返回第一页也能正常显示。求大家帮忙看一下是哪里出现了问题。
package com.example.tian.himeccbyclpad.frament; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.FrameLayout; import android.widget.GridView; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import com.example.tian.himeccbyclpad.R; import com.example.tian.himeccbyclpad.common.Constant; import com.example.tian.himeccbyclpad.factory.PagerFactory; import com.example.tian.himeccbyclpad.view.Pager; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; /** * A simple {@link Fragment} subclass. * Activities that contain this fragment must implement the * {@link OnFragmentInteractionListener} interface * to handle interaction events. * Use the {@link WriteFragment#newInstance} factory method to * create an instance of this fragment. */ public class WriteFragment extends Fragment { // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private static final String ARG_PARAM1 = "param1"; private static final String ARG_PARAM2 = "param2"; private static final String TAG = "WriteFragment"; private Unbinder unbinder; @BindView(R.id.book_grid_view) GridView bookGridView; // TODO: Rename and change types of parameters private String mParam1; private String mParam2; FrameLayout view; private OnFragmentInteractionListener mListener; private Pager mPager; Bitmap mCurPageBitmap, mNextPageBitmap; Canvas mCurPageCanvas, mNextPageCanvas; PagerFactory pagerFactory; private List<Map<String,String>> bookList; private BooksAdapter booksAdapter; private ImageView mListenBookIV; private WriteFragment writeFragment; private XimalayaFragment ximalayaFragment; public WriteFragment() { // Required empty public constructor } /** * Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param param1 Parameter 1. * @param param2 Parameter 2. * @return A new instance of fragment WriteFragment. */ // TODO: Rename and change types and number of parameters public static WriteFragment newInstance(String param1, String param2) { WriteFragment fragment = new WriteFragment(); Bundle args = new Bundle(); args.putString(ARG_PARAM1, param1); args.putString(ARG_PARAM2, param2); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { view = (FrameLayout) inflater.inflate(R.layout.fragment_write, container, false); mListenBookIV = view.findViewById(R.id.listen_book_iv); unbinder = ButterKnife.bind(this,view); ButterKnife.bind(this, view); // Inflate the layout for this fragment initEvent(); initBookShelf(); return view; } private void initEvent() { mListenBookIV.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FragmentManager fragmentManager = getFragmentManager(); // 开启事务 assert fragmentManager != null; FragmentTransaction transaction = fragmentManager.beginTransaction(); //隐藏Fragment hideFragment(transaction); if (ximalayaFragment == null) { //writeFragment = new XinWriteFragment(); ximalayaFragment = new XimalayaFragment(); transaction.add(R.id.content, ximalayaFragment); } else { transaction.show(ximalayaFragment); } transaction.commit(); } }); } private void hideFragment(FragmentTransaction transaction) { if (ximalayaFragment != null){ transaction.hide(ximalayaFragment); } if (writeFragment != null) { transaction.hide(writeFragment); } } /*初始化书架界面*/ public void initBookShelf(){ bookGridView.setVisibility(View.VISIBLE); /*读取小说列表*/ File file = new File(Environment.getExternalStorageDirectory().getPath() + Constant.APP_DIR + "/books/"); if (!file.exists()) { file.mkdir(); } /*小说封面图片目录*/ File imgFile = new File(Environment.getExternalStorageDirectory().getPath() + Constant.APP_DIR + "/booksImg/"); if (!imgFile.exists()) { imgFile.mkdir(); } File[] fileList = file.listFiles(); bookList = new ArrayList<Map<String, String>>(); Map<String,String> map=null; for (File book : fileList) { if (book != null) { map=new HashMap<String,String>(); map.put("text",book.getName().substring(0,book.getName().lastIndexOf("."))); map.put("img",imgFile+"/"+book.getName().substring(0,book.getName().lastIndexOf("."))+".png"); bookList.add(map); } } booksAdapter=new BooksAdapter(getContext(),bookList); bookGridView.setAdapter(booksAdapter); } /*初始化阅读界面*/ public void initMpager(){ DisplayMetrics dm = this.getResources().getDisplayMetrics(); int screenWidth = dm.widthPixels; int screenHeight = dm.heightPixels; if(mPager==null) { mPager = new Pager(getContext(), screenWidth, screenHeight); mCurPageBitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888); mNextPageBitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888); mCurPageCanvas = new Canvas(mCurPageBitmap); mNextPageCanvas = new Canvas(mNextPageBitmap); pagerFactory = new PagerFactory(screenWidth, screenHeight); pagerFactory.setBgBitmap(BitmapFactory.decodeResource(this.getResources(), R.drawable.read_bg)); view.addView(mPager); bookGridView.setVisibility(View.GONE); } } /*打开书本*/ @SuppressLint("ClickableViewAccessibility") private void openBook(String path, int progress){ try { // write2sd("test.txt"); pagerFactory.openbook(path,progress); pagerFactory.onDraw(mCurPageCanvas); } catch (IOException e1) { e1.printStackTrace(); Toast.makeText(getContext(), "电子书不存在!请把电子书放到本地目录下...", Toast.LENGTH_SHORT).show(); } mPager.setBitmaps(mCurPageBitmap, mCurPageBitmap); mPager.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent e) { boolean ret = false; if (v == mPager) { if (e.getAction() == MotionEvent.ACTION_DOWN) { mPager.calcCornerXY(e.getX(), e.getY()); mPager.abortAnimation(); pagerFactory.onDraw(mCurPageCanvas); if (mPager.DragToRight()) { // 向右滑动,显示前一页 try { pagerFactory.prePage(); } catch (IOException e1) { e1.printStackTrace(); } if (pagerFactory.isfirstPage()) { return false; } pagerFactory.onDraw(mNextPageCanvas); } else { // 向左滑动,显示后一页 try { pagerFactory.nextPage(); } catch (IOException e1) { e1.printStackTrace(); } if (pagerFactory.islastPage()) { return false; } pagerFactory.onDraw(mNextPageCanvas); } mPager.setBitmaps(mCurPageBitmap, mNextPageBitmap); } ret = mPager.doTouchEvent(e); return ret; } return false; } }); } /*释放阅读界面资源*/ public void freeMpager(){ if(mPager!=null) { view.removeView(mPager); mPager = null; mCurPageBitmap = null; mNextPageBitmap = null; mCurPageCanvas.setBitmap(null); mNextPageCanvas.setBitmap(null); mCurPageCanvas = null; mNextPageCanvas = null; pagerFactory.setBgBitmap(null); pagerFactory = null; } } // TODO: Rename method, update argument and hook method into UI event public void onButtonPressed(Uri uri) { if (mListener != null) { mListener.onFragmentInteraction(uri); } } @Override public void onAttach(Context context) { super.onAttach(context); } @Override public void onDetach() { super.onDetach(); mListener = null; } @Override public void onDestroyView() { super.onDestroyView(); unbinder.unbind(); //ButterKnife.reset(this); } /** * This interface must be implemented by activities that contain this * fragment to allow an interaction in this fragment to be communicated * to the activity and potentially other fragments contained in that * activity. * <p/> * See the Android Training lesson <a href= * "http://developer.android.com/training/basics/fragments/communicating.html" * >Communicating with Other Fragments</a> for more information. */ public interface OnFragmentInteractionListener { // TODO: Update argument type and name void onFragmentInteraction(Uri uri); } private void write2sd(String fileName) { String text = "null"; try { InputStream is = getResources().getAssets().open(fileName); int len = is.available(); byte[] buffer = new byte[len]; is.read(buffer); text = new String(buffer, "utf-8"); is.close(); } catch (Exception e) { e.printStackTrace(); } try { FileOutputStream os = new FileOutputStream(new File(fileName)); byte[] buffer = text.getBytes(); os.write(buffer); os.close(); } catch (Exception e) { e.printStackTrace(); } } public class BooksAdapter extends BaseAdapter { private List<Map<String, String>> list; private Context context; private LayoutInflater mInflater; public BooksAdapter(Context context, List<Map<String, String>> list) { this.context = context; this.list = list; mInflater = LayoutInflater.from(context); } @Override public int getCount() { // TODO Auto-generated method stub return list.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder hold = null; if (convertView == null) { hold = new ViewHolder(); convertView = mInflater.inflate(R.layout.book_item_view, null); hold.img = (ImageView) convertView.findViewById(R.id.img); hold.text = (TextView) convertView.findViewById(R.id.text); convertView.setTag(hold); } else { hold = (ViewHolder) convertView.getTag(); } hold.text.setText("《"+(String) list.get(position).get("text")+"》"); File img=new File(list.get(position).get("img")); if(img!=null&&img.exists()){ hold.img.setImageBitmap(BitmapFactory.decodeFile(img.getAbsolutePath()) ); }else{ hold.img.setImageBitmap(BitmapFactory.decodeResource(WriteFragment.this.getContext().getResources(),R.drawable.book_devault) ); } final int p=position; convertView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { initMpager(); openBook(Environment.getExternalStorageDirectory().getPath() + Constant.APP_DIR + "/books/"+(String) list.get(p).get("text")+".txt",0); } }); return convertView; } private final class ViewHolder { private ImageView img; private TextView text; } } } /** * Author : hmg25 * Description : */ package com.example.tian.himeccbyclpad.factory; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.text.DecimalFormat; import java.util.Vector; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; public class PagerFactory { private File book_file = null; private MappedByteBuffer m_mbBuf = null; private int m_mbBufLen = 0; private int m_mbBufBegin = 0; private int m_mbBufEnd = 0; private String encode = "utf-8"; private Bitmap m_book_bg = null; private int mWidth; private int mHeight; private Vector<String> m_lines = new Vector<String>(); private int m_fontSize = 28; private int m_textColor = Color.BLACK; private int m_backColor = 0xffff9e85; // 背景颜色 private int marginWidth = 40; // 左右与边缘的距离 private int marginHeight = 20; // 上下与边缘的距离 private int mLineCount; // 每页可以显示的行数 private float mVisibleHeight; // 绘制内容的宽 private float mVisibleWidth; // 绘制内容的宽 private boolean m_isfirstPage,m_islastPage; // private int m_nLineSpaceing = 5; private Paint mPaint; public PagerFactory(int w, int h) { mWidth = w; mHeight = h; mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setTextAlign(Align.LEFT); mPaint.setTextSize(m_fontSize); mPaint.setColor(m_textColor); mVisibleWidth = mWidth - marginWidth * 2; mVisibleHeight = mHeight - marginHeight * 2; mLineCount = (int) (mVisibleHeight / m_fontSize); // 可显示的行数 } public void openbook(String strFilePath,int progress) throws IOException { book_file = new File(strFilePath); long lLen = book_file.length(); m_mbBufLen = (int) lLen; m_mbBuf = new RandomAccessFile(book_file, "r").getChannel().map(FileChannel.MapMode.READ_ONLY, 0, lLen); m_mbBufEnd=progress; } protected byte[] readParagraphBack(int nFromPos) { int nEnd = nFromPos; int i; byte b0, b1; if (encode.equals("UTF-16LE")) { i = nEnd - 2; while (i > 0) { b0 = m_mbBuf.get(i); b1 = m_mbBuf.get(i + 1); if (b0 == 0x0a && b1 == 0x00 && i != nEnd - 2) { i += 2; break; } i--; } } else if (encode.equals("UTF-16BE")) { i = nEnd - 2; while (i > 0) { b0 = m_mbBuf.get(i); b1 = m_mbBuf.get(i + 1); if (b0 == 0x00 && b1 == 0x0a && i != nEnd - 2) { i += 2; break; } i--; } } else { i = nEnd - 1; while (i > 0) { b0 = m_mbBuf.get(i); if (b0 == 0x0a && i != nEnd - 1) { i++; break; } i--; } } if (i < 0) i = 0; int nParaSize = nEnd - i; int j; byte[] buf = new byte[nParaSize]; for (j = 0; j < nParaSize; j++) { buf[j] = m_mbBuf.get(i + j); } return buf; } // 读取上一段落 protected byte[] readParagraphForward(int nFromPos) { int nStart = nFromPos; int i = nStart; byte b0, b1; // 根据编码格式判断换行 if (encode.equals("UTF-16LE")) { while (i < m_mbBufLen - 1) { b0 = m_mbBuf.get(i++); b1 = m_mbBuf.get(i++); if (b0 == 0x0a && b1 == 0x00) { break; } } } else if (encode.equals("UTF-16BE")) { while (i < m_mbBufLen - 1) { b0 = m_mbBuf.get(i++); b1 = m_mbBuf.get(i++); if (b0 == 0x00 && b1 == 0x0a) { break; } } } else { while (i < m_mbBufLen) { b0 = m_mbBuf.get(i++); if (b0 == 0x0a) { break; } } } int nParaSize = i - nStart; byte[] buf = new byte[nParaSize]; for (i = 0; i < nParaSize; i++) { buf[i] = m_mbBuf.get(nFromPos + i); } return buf; } protected Vector<String> pageDown() { String strParagraph = ""; Vector<String> lines = new Vector<String>(); while (lines.size() < mLineCount && m_mbBufEnd < m_mbBufLen) { byte[] paraBuf = readParagraphForward(m_mbBufEnd); // 读取一个段落 m_mbBufEnd += paraBuf.length; try { strParagraph = new String(paraBuf, encode); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } String strReturn = ""; //if (strParagraph.indexOf("\r\n") != -1) { if (strParagraph.contains("\r\n")) { strReturn = "\r\n"; strParagraph = strParagraph.replaceAll("\r\n", ""); //} else if (strParagraph.indexOf("\n") != -1) { } else if (strParagraph.contains("\n")) { strReturn = "\n"; strParagraph = strParagraph.replaceAll("\n", ""); } if (strParagraph.length() == 0) { lines.add(strParagraph); } while (strParagraph.length() > 0) { int nSize = mPaint.breakText(strParagraph, true, mVisibleWidth, null); lines.add(strParagraph.substring(0, nSize)); strParagraph = strParagraph.substring(nSize); if (lines.size() >= mLineCount) { break; } } if (strParagraph.length() != 0) { try { m_mbBufEnd -= (strParagraph + strReturn).getBytes(encode).length; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } return lines; } protected void pageUp() { if (m_mbBufBegin < 0) m_mbBufBegin = 0; Vector<String> lines = new Vector<String>(); String strParagraph = ""; while (lines.size() < mLineCount && m_mbBufBegin > 0) { Vector<String> paraLines = new Vector<String>(); byte[] paraBuf = readParagraphBack(m_mbBufBegin); m_mbBufBegin -= paraBuf.length; try { strParagraph = new String(paraBuf, encode); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } strParagraph = strParagraph.replaceAll("\r\n", ""); strParagraph = strParagraph.replaceAll("\n", ""); if (strParagraph.length() == 0) { paraLines.add(strParagraph); } while (strParagraph.length() > 0) { int nSize = mPaint.breakText(strParagraph, true, mVisibleWidth, null); paraLines.add(strParagraph.substring(0, nSize)); strParagraph = strParagraph.substring(nSize); } lines.addAll(0, paraLines); } while (lines.size() > mLineCount) { try { m_mbBufBegin += lines.get(0).getBytes(encode).length; lines.remove(0); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } m_mbBufEnd = m_mbBufBegin; return; } public void prePage() throws IOException { if (m_mbBufBegin <= 0) { m_mbBufBegin = 0; m_isfirstPage=true; return; }else m_isfirstPage=false; m_lines.clear(); pageUp(); m_lines = pageDown(); } public void nextPage() throws IOException { if (m_mbBufEnd >= m_mbBufLen) { m_islastPage=true; return; }else m_islastPage=false; m_lines.clear(); m_mbBufBegin = m_mbBufEnd; m_lines = pageDown(); } public void onDraw(Canvas c) { if (m_lines.size() == 0) m_lines = pageDown(); if (m_lines.size() > 0) { if (m_book_bg == null) c.drawColor(m_backColor); else c.drawBitmap(m_book_bg, 0, 0, null); int y = marginHeight; for (String strLine : m_lines) { y += m_fontSize; c.drawText(strLine, marginWidth, y, mPaint); } } float fPercent = (float) (m_mbBufEnd * 1.0 / m_mbBufLen); DecimalFormat df = new DecimalFormat("#0.0"); String strPercent = df.format(fPercent * 100) + "%"; int nPercentWidth = (int) mPaint.measureText("999.9%") + 1; c.drawText(strPercent, mWidth - nPercentWidth, mHeight - 5, mPaint); } public void setBgBitmap(Bitmap BG) { m_book_bg = BG; } public boolean isfirstPage() { return m_isfirstPage; } public boolean islastPage() { return m_islastPage; } } package com.example.tian.himeccbyclpad.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PointF; import android.graphics.Region; import android.graphics.drawable.GradientDrawable; import android.os.Build; import android.view.MotionEvent; import android.view.View; import android.widget.Scroller; import com.example.tian.himeccbyclpad.util.LogUtil; public class Pager extends View { private int mWidth = 480; private int mHeight = 800; private int mCornerX = 0; // 拖拽点对应的页脚 private int mCornerY = 0; private Path mPath0; private Path mPath1; //Bitmap mCurPageBitmap = null; Bitmap mCurPageBitmap = null; // 当前页 Bitmap mNextPageBitmap = null; PointF mTouch = new PointF(); // 拖拽点 PointF mBezierStart1 = new PointF(); // 贝塞尔曲线起始点 PointF mBezierControl1 = new PointF(); // 贝塞尔曲线控制点 PointF mBeziervertex1 = new PointF(); // 贝塞尔曲线顶点 PointF mBezierEnd1 = new PointF(); // 贝塞尔曲线结束点 PointF mBezierStart2 = new PointF(); // 另一条贝塞尔曲线 PointF mBezierControl2 = new PointF(); PointF mBeziervertex2 = new PointF(); PointF mBezierEnd2 = new PointF(); float mMiddleX; float mMiddleY; float mDegrees; float mTouchToCornerDis; ColorMatrixColorFilter mColorMatrixFilter; Matrix mMatrix; float[] mMatrixArray = { 0, 0, 0, 0, 0, 0, 0, 0, 1.0f }; boolean mIsRTandLB; // 是否属于右、上、左、下 float mMaxLength = (float) Math.hypot(mWidth, mHeight); int[] mBackShadowColors; int[] mFrontShadowColors; GradientDrawable mBackShadowDrawableLR; GradientDrawable mBackShadowDrawableRL; GradientDrawable mFolderShadowDrawableLR; GradientDrawable mFolderShadowDrawableRL; GradientDrawable mFrontShadowDrawableHBT; GradientDrawable mFrontShadowDrawableHTB; GradientDrawable mFrontShadowDrawableVLR; GradientDrawable mFrontShadowDrawableVRL; Paint mPaint; Scroller mScroller; boolean touchflag=false; public Pager(Context context, int screenWidth, int screenHeight) { super(context); this.mWidth = screenWidth; // Pager 宽和高 this.mHeight = screenHeight; mPath0 = new Path(); mPath1 = new Path(); createDrawable(); mPaint = new Paint(); mPaint.setStyle(Paint.Style.FILL); ColorMatrix cm = new ColorMatrix(); float array[] = { 0.55f, 0, 0, 0, 80.0f, 0, 0.55f, 0, 0, 80.0f, 0, 0, 0.55f, 0, 80.0f, 0, 0, 0, 0.2f, 0 }; cm.set(array); mColorMatrixFilter = new ColorMatrixColorFilter(cm); mMatrix = new Matrix(); mScroller = new Scroller(getContext()); mTouch.x = 0.01f; // 不让x,y为0,否则在点计算时会有问题 mTouch.y = 0.01f; } /** 计算拖拽点对应的拖拽脚 */ public void calcCornerXY(float x, float y) { if (x <= mWidth / 2) mCornerX = 0; else mCornerX = mWidth; if (y <= mHeight / 2) mCornerY = 0; else mCornerY = mHeight; if ((mCornerX == 0 && mCornerY == mHeight) || (mCornerX == mWidth && mCornerY == 0)) mIsRTandLB = true; else mIsRTandLB = false; } public boolean doTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_MOVE) { mTouch.x = event.getX(); mTouch.y = event.getY(); this.postInvalidate(); } if (event.getAction() == MotionEvent.ACTION_DOWN) { mTouch.x = event.getX(); mTouch.y = event.getY(); // calcCornerXY(mTouch.x, mTouch.y); // this.postInvalidate(); } if (event.getAction() == MotionEvent.ACTION_UP) { if (canDragOver()) { startAnimation(1200); } else { mTouch.x = mCornerX - 0.09f; mTouch.y = mCornerY - 0.09f; } this.postInvalidate(); } // return super.onTouchEvent(event); return true; } /** 求解直线P1P2和直线P3P4的交点坐标 */ public PointF getCross(PointF P1, PointF P2, PointF P3, PointF P4) { PointF CrossP = new PointF(); // 二元函数通式: y=ax+b float a1 = (P2.y - P1.y) / (P2.x - P1.x); float b1 = ((P1.x * P2.y) - (P2.x * P1.y)) / (P1.x - P2.x); float a2 = (P4.y - P3.y) / (P4.x - P3.x); float b2 = ((P3.x * P4.y) - (P4.x * P3.y)) / (P3.x - P4.x); CrossP.x = (b2 - b1) / (a1 - a2); CrossP.y = a1 * CrossP.x + b1; return CrossP; } private void calcPoints() { mMiddleX = (mTouch.x + mCornerX) / 2; mMiddleY = (mTouch.y + mCornerY) / 2; mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX); mBezierControl1.y = mCornerY; mBezierControl2.x = mCornerX; mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY); mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2; mBezierStart1.y = mCornerY; // 当mBezierStart1.x < 0或者mBezierStart1.x > 480时 // 如果继续翻页,会出现BUG故在此限制 if (mTouch.x > 0 && mTouch.x < mWidth) { if (mBezierStart1.x < 0 || mBezierStart1.x > mWidth) { if (mBezierStart1.x < 0) mBezierStart1.x = mWidth - mBezierStart1.x; float f1 = Math.abs(mCornerX - mTouch.x); float f2 = mWidth * f1 / mBezierStart1.x; mTouch.x = Math.abs(mCornerX - f2); float f3 = Math.abs(mCornerX - mTouch.x) * Math.abs(mCornerY - mTouch.y) / f1; mTouch.y = Math.abs(mCornerY - f3); mMiddleX = (mTouch.x + mCornerX) / 2; mMiddleY = (mTouch.y + mCornerY) / 2; mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX); mBezierControl1.y = mCornerY; mBezierControl2.x = mCornerX; mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY); mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2; } } mBezierStart2.x = mCornerX; mBezierStart2.y = mBezierControl2.y - (mCornerY - mBezierControl2.y) / 2; mTouchToCornerDis = (float) Math.hypot((mTouch.x - mCornerX), (mTouch.y - mCornerY)); mBezierEnd1 = getCross(mTouch, mBezierControl1, mBezierStart1, mBezierStart2); mBezierEnd2 = getCross(mTouch, mBezierControl2, mBezierStart1, mBezierStart2); /* * mBeziervertex1.x 推导 * ((mBezierStart1.x+mBezierEnd1.x)/2+mBezierControl1.x)/2 化简等价于 * (mBezierStart1.x+ 2*mBezierControl1.x+mBezierEnd1.x) / 4 */ mBeziervertex1.x = (mBezierStart1.x + 2 * mBezierControl1.x + mBezierEnd1.x) / 4; mBeziervertex1.y = (2 * mBezierControl1.y + mBezierStart1.y + mBezierEnd1.y) / 4; mBeziervertex2.x = (mBezierStart2.x + 2 * mBezierControl2.x + mBezierEnd2.x) / 4; mBeziervertex2.y = (2 * mBezierControl2.y + mBezierStart2.y + mBezierEnd2.y) / 4; } private void drawCurrentPageArea(Canvas canvas, Bitmap bitmap, Path path) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){ mPath0.reset(); mPath0.moveTo(mBezierStart1.x, mBezierStart1.y); mPath0.quadTo(mBezierControl1.x, mBezierControl1.y, mBezierEnd1.x, mBezierEnd1.y); mPath0.lineTo(mTouch.x, mTouch.y); mPath0.lineTo(mBezierEnd2.x, mBezierEnd2.y); mPath0.quadTo(mBezierControl2.x, mBezierControl2.y, mBezierStart2.x, mBezierStart2.y); mPath0.lineTo(mCornerX, mCornerY); mPath0.close(); canvas.save(); //版本判断 //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){ canvas.clipPath(path); canvas.drawBitmap(bitmap, 0, 0, null); canvas.restore(); }else { canvas.clipPath(path,Region.Op.REPLACE); canvas.drawBitmap(bitmap, 0, 0, null); canvas.restore(); } } private void drawNextPageAreaAndShadow(Canvas canvas, Bitmap bitmap) { mPath1.reset(); mPath1.moveTo(mBezierStart1.x, mBezierStart1.y); mPath1.lineTo(mBeziervertex1.x, mBeziervertex1.y); mPath1.lineTo(mBeziervertex2.x, mBeziervertex2.y); mPath1.lineTo(mBezierStart2.x, mBezierStart2.y); mPath1.lineTo(mCornerX, mCornerY); mPath1.close(); mDegrees = (float) Math.toDegrees(Math.atan2(mBezierControl1.x - mCornerX, mBezierControl2.y - mCornerY)); int leftx; int rightx; GradientDrawable mBackShadowDrawable; if (mIsRTandLB) { leftx = (int) (mBezierStart1.x); rightx = (int) (mBezierStart1.x + mTouchToCornerDis / 4); mBackShadowDrawable = mBackShadowDrawableLR; } else { leftx = (int) (mBezierStart1.x - mTouchToCornerDis / 4); rightx = (int) mBezierStart1.x; mBackShadowDrawable = mBackShadowDrawableRL; } canvas.save(); //版本判断 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){ canvas.clipPath(mPath0); canvas.clipPath(mPath1); }else { canvas.clipPath(mPath1,Region.Op.INTERSECT); } //canvas.clipPath(mPath1, Region.Op.INTERSECT); canvas.drawBitmap(bitmap, 0, 0, null); canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y); mBackShadowDrawable.setBounds(leftx, (int) mBezierStart1.y, rightx, (int) (mMaxLength + mBezierStart1.y)); mBackShadowDrawable.draw(canvas); canvas.restore(); } public void setBitmaps(Bitmap bm1, Bitmap bm2) { mCurPageBitmap = bm1; mNextPageBitmap = bm2; } public void setScreen(int w, int h) { mWidth = w; mHeight = h; } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(0xFFAAAAAA); float x=mTouch.x; float y=mTouch.y; LogUtil.e("x:"+x+" y:"+y); if(y>=0&&y<=mHeight-1) { calcPoints(); drawCurrentPageArea(canvas, mCurPageBitmap, mPath0); drawNextPageAreaAndShadow(canvas, mNextPageBitmap); drawCurrentPageShadow(canvas); drawCurrentBackArea(canvas, mCurPageBitmap); }else{ mCurPageBitmap=mNextPageBitmap; canvas.drawBitmap(mCurPageBitmap,0,0,null); } } /** 创建阴影的GradientDrawable */ private void createDrawable() { int[] color = { 0x333333, 0xb0333333 }; mFolderShadowDrawableRL = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, color); mFolderShadowDrawableRL.setGradientType(GradientDrawable.LINEAR_GRADIENT); mFolderShadowDrawableLR = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, color); mFolderShadowDrawableLR.setGradientType(GradientDrawable.LINEAR_GRADIENT); mBackShadowColors = new int[] { 0xff111111, 0x111111 }; mBackShadowDrawableRL = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, mBackShadowColors); mBackShadowDrawableRL.setGradientType(GradientDrawable.LINEAR_GRADIENT); mBackShadowDrawableLR = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, mBackShadowColors); mBackShadowDrawableLR.setGradientType(GradientDrawable.LINEAR_GRADIENT); mFrontShadowColors = new int[] { 0x80111111, 0x111111 }; mFrontShadowDrawableVLR = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, mFrontShadowColors); mFrontShadowDrawableVLR.setGradientType(GradientDrawable.LINEAR_GRADIENT); mFrontShadowDrawableVRL = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, mFrontShadowColors); mFrontShadowDrawableVRL.setGradientType(GradientDrawable.LINEAR_GRADIENT); mFrontShadowDrawableHTB = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, mFrontShadowColors); mFrontShadowDrawableHTB.setGradientType(GradientDrawable.LINEAR_GRADIENT); mFrontShadowDrawableHBT = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, mFrontShadowColors); mFrontShadowDrawableHBT.setGradientType(GradientDrawable.LINEAR_GRADIENT); } /** 绘制翻起页的阴影 */ public void drawCurrentPageShadow(Canvas canvas) { double degree; if (mIsRTandLB) { degree = Math.PI / 4 - Math.atan2(mBezierControl1.y - mTouch.y, mTouch.x - mBezierControl1.x); } else { degree = Math.PI / 4 - Math.atan2(mTouch.y - mBezierControl1.y, mTouch.x - mBezierControl1.x); } // 翻起页阴影顶点与touch点的距离 double d1 = (float) 25 * 1.414 * Math.cos(degree); double d2 = (float) 25 * 1.414 * Math.sin(degree); float x = (float) (mTouch.x + d1); float y; if (mIsRTandLB) { y = (float) (mTouch.y + d2); } else { y = (float) (mTouch.y - d2); } mPath1.reset(); mPath1.moveTo(x, y); mPath1.lineTo(mTouch.x, mTouch.y); mPath1.lineTo(mBezierControl1.x, mBezierControl1.y); mPath1.lineTo(mBezierStart1.x, mBezierStart1.y); mPath1.close(); float rotateDegrees; canvas.save(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){ Path mPathXOR = new Path(); mPathXOR.moveTo(0,0); mPathXOR.lineTo(getWidth(),0); mPathXOR.lineTo(getWidth(),getHeight()); mPathXOR.lineTo(0,getHeight()); mPathXOR.close(); //以上根据实际的Canvas或View的大小,画出相同大小的Path即可 mPathXOR.op(mPath0, Path.Op.XOR); canvas.clipPath(mPathXOR); canvas.clipPath(mPath1); }else { canvas.clipPath(mPath0,Region.Op.XOR); canvas.clipPath(mPath1,Region.Op.INTERSECT); } /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){ canvas.clipPath(mPath1); }else { canvas.clipPath(mPath1,Region.Op.INTERSECT); }*/ //canvas.clipPath(mPath0, Region.Op.XOR); //canvas.clipPath(mPath1, Region.Op.INTERSECT); int leftx; int rightx; GradientDrawable mCurrentPageShadow; if (mIsRTandLB) { leftx = (int) (mBezierControl1.x); rightx = (int) mBezierControl1.x + 25; mCurrentPageShadow = mFrontShadowDrawableVLR; } else { leftx = (int) (mBezierControl1.x - 25); rightx = (int) mBezierControl1.x + 1; mCurrentPageShadow = mFrontShadowDrawableVRL; } rotateDegrees = (float) Math.toDegrees(Math.atan2(mTouch.x - mBezierControl1.x, mBezierControl1.y - mTouch.y)); canvas.rotate(rotateDegrees, mBezierControl1.x, mBezierControl1.y); mCurrentPageShadow.setBounds(leftx, (int) (mBezierControl1.y - mMaxLength), rightx, (int) (mBezierControl1.y)); mCurrentPageShadow.draw(canvas); canvas.restore(); mPath1.reset(); mPath1.moveTo(x, y); mPath1.lineTo(mTouch.x, mTouch.y); mPath1.lineTo(mBezierControl2.x, mBezierControl2.y); mPath1.lineTo(mBezierStart2.x, mBezierStart2.y); mPath1.close(); canvas.save(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){ Path mPathXOR = new Path(); mPathXOR.moveTo(0,0); mPathXOR.lineTo(getWidth(),0); mPathXOR.lineTo(getWidth(),getHeight()); mPathXOR.lineTo(0,getHeight()); mPathXOR.close(); //以上根据实际的Canvas或View的大小,画出相同大小的Path即可 mPathXOR.op(mPath0, Path.Op.XOR); canvas.clipPath(mPathXOR); canvas.clipPath(mPath1); }else { canvas.clipPath(mPath0,Region.Op.XOR); canvas.clipPath(mPath1,Region.Op.INTERSECT); } /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){ canvas.clipPath(mPath1); }else { canvas.clipPath(mPath1,Region.Op.INTERSECT); }*/ // canvas.clipPath(mPath0, Region.Op.XOR); // canvas.clipPath(mPath1, Region.Op.INTERSECT); if (mIsRTandLB) { leftx = (int) (mBezierControl2.y); rightx = (int) (mBezierControl2.y + 25); mCurrentPageShadow = mFrontShadowDrawableHTB; } else { leftx = (int) (mBezierControl2.y - 25); rightx = (int) (mBezierControl2.y + 1); mCurrentPageShadow = mFrontShadowDrawableHBT; } rotateDegrees = (float) Math.toDegrees(Math.atan2(mBezierControl2.y - mTouch.y, mBezierControl2.x - mTouch.x)); canvas.rotate(rotateDegrees, mBezierControl2.x, mBezierControl2.y); float temp; if (mBezierControl2.y < 0) temp = mBezierControl2.y - mHeight; else temp = mBezierControl2.y; int hmg = (int) Math.hypot(mBezierControl2.x, temp); if (hmg > mMaxLength) mCurrentPageShadow.setBounds((int) (mBezierControl2.x - 25) - hmg, leftx, (int) (mBezierControl2.x + mMaxLength) - hmg, rightx); else mCurrentPageShadow.setBounds((int) (mBezierControl2.x - mMaxLength), leftx, (int) (mBezierControl2.x), rightx); mCurrentPageShadow.draw(canvas); canvas.restore(); } /** 绘制翻起页背面 */ private void drawCurrentBackArea(Canvas canvas, Bitmap bitmap) { int i = (int) (mBezierStart1.x + mBezierControl1.x) / 2; float f1 = Math.abs(i - mBezierControl1.x); int i1 = (int) (mBezierStart2.y + mBezierControl2.y) / 2; float f2 = Math.abs(i1 - mBezierControl2.y); float f3 = Math.min(f1, f2); mPath1.reset(); mPath1.moveTo(mBeziervertex2.x, mBeziervertex2.y); mPath1.lineTo(mBeziervertex1.x, mBeziervertex1.y); mPath1.lineTo(mBezierEnd1.x, mBezierEnd1.y); mPath1.lineTo(mTouch.x, mTouch.y); mPath1.lineTo(mBezierEnd2.x, mBezierEnd2.y); mPath1.close(); GradientDrawable mFolderShadowDrawable; int left; int right; if (mIsRTandLB) { left = (int) (mBezierStart1.x - 1); right = (int) (mBezierStart1.x + f3 + 1); mFolderShadowDrawable = mFolderShadowDrawableLR; } else { left = (int) (mBezierStart1.x - f3 - 1); right = (int) (mBezierStart1.x + 1); mFolderShadowDrawable = mFolderShadowDrawableRL; } canvas.save(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){ canvas.clipPath(mPath0); canvas.clipPath(mPath1); }else { canvas.clipPath(mPath1,Region.Op.INTERSECT); } // canvas.clipPath(mPath1, Region.Op.INTERSECT); mPaint.setColorFilter(mColorMatrixFilter); float dis = (float) Math.hypot(mCornerX - mBezierControl1.x, mBezierControl2.y - mCornerY); float f8 = (mCornerX - mBezierControl1.x) / dis; float f9 = (mBezierControl2.y - mCornerY) / dis; mMatrixArray[0] = 1 - 2 * f9 * f9; mMatrixArray[1] = 2 * f8 * f9; mMatrixArray[3] = mMatrixArray[1]; mMatrixArray[4] = 1 - 2 * f8 * f8; mMatrix.reset(); mMatrix.setValues(mMatrixArray); mMatrix.preTranslate(-mBezierControl1.x, -mBezierControl1.y); mMatrix.postTranslate(mBezierControl1.x, mBezierControl1.y); canvas.drawBitmap(bitmap, mMatrix, mPaint); // canvas.drawBitmap(bitmap, mMatrix, null); mPaint.setColorFilter(null); canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y); mFolderShadowDrawable.setBounds(left, (int) mBezierStart1.y, right, (int) (mBezierStart1.y + mMaxLength)); mFolderShadowDrawable.draw(canvas); canvas.restore(); } public void computeScroll() { super.computeScroll(); if (mScroller.computeScrollOffset()) { float x = mScroller.getCurrX(); float y = mScroller.getCurrY(); mTouch.x = x; mTouch.y = y; postInvalidate(); }else if(touchflag){//此次滚动由人为触摸 touchflag=false; /*float x=mTouch.x; float y=mTouch.y; LogUtil.e("结束x:"+x+" y:"+y);*/ //mCurPageBitmap=mNextPageBitmap; //postInvalidate(); } } private void startAnimation(int delayMillis) { touchflag=true; int dx, dy; // dx 水平方向滑动的距离,负值会使滚动向左滚动 dy 垂直方向滑动的距离,负值会使滚动向上滚动 if (mCornerX > 0) { dx = -(int) (mWidth + mTouch.x); } else { dx = (int) (mWidth - mTouch.x + mWidth); } if (mCornerY > 0) { dy = (int) (mHeight - mTouch.y); } else { dy = (int) (1 - mTouch.y); // 防止mTouch.y最终变为0 } mScroller.startScroll((int) mTouch.x, (int) mTouch.y, dx, dy, delayMillis); } public void abortAnimation() { if (!mScroller.isFinished()) { mScroller.abortAnimation(); // mCurPageBitmap=mNextPageBitmap; touchflag=false; mTouch.y=mHeight; postInvalidate(); } } public boolean canDragOver() { /*if (mTouchToCornerDis > mWidth / 10) return true; return false;*/ return true; } /** 是否从左边翻向右边 */ public boolean DragToRight() { if (mCornerX > 0) return false; return true; } }
感谢您的回答
您的每一个用心回答,都会让这个世界变得更美好一些!
相关问题
kissmyass ·
Androidstudio
2019-12-18 06:26 847 3
2019-12-21 22:25 821 10
所以,你要判断你的页面bitmap是否创建成功,这么多条件。有没有执行到绘制文字的地方。加Log,打断点。自己定位一下问题。
这里为什么两个都一样呢?mPager.setBitmaps(mCurPageBitmap, mCurPageBitmap);
不是一个当前页,一个下一页吗?
怎么有喜马拉雅的fragment的?这么神奇
对于这种问题,要判断。数据是否到位了。
如果数据有了,就判断绘制条件。
你的页面mCurrentBitmap是从外部设置进来的setBitmaps,一步一步去纠问题,定位出来.