在读取本地小说显示的时候,第一页总是显示阴影界面,从第二页会正常显示,从第二页返回第一页也能正常显示。求大家帮忙看一下是哪里出现了问题。
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;
}
}
求大神们帮忙看一下,非常谢谢。