余乐115 2020-05-11 10:48 采纳率: 33.3%
浏览 196
已结题

加载本地小说第一页显示不出来。

在读取本地小说显示的时候,第一页总是显示阴影界面,从第二页会正常显示,从第二页返回第一页也能正常显示。求大家帮忙看一下是哪里出现了问题。

图片说明图片说明

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;
    }

}

求大神们帮忙看一下,非常谢谢。

  • 写回答

1条回答 默认 最新

  • dabocaiqq 2020-05-12 09:27
    关注
    评论

报告相同问题?

悬赏问题

  • ¥15 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?