Android自定義View——從零開始實現書籍翻頁效果(二)

版權聲明:本文爲博主原創文章,未經博主容許不得轉載html

系列教程:Android開發之從零開始系列java

源碼:AnliaLee/BookPage,歡迎starandroid

你們要是看到有錯誤的地方或者有啥好的建議,歡迎留言評論git

前言:在上篇Android自定義View——從零開始實現書籍翻頁效果(一)博客中,咱們實現了 基本的上下翻頁效果右側最大翻頁距離的限制,這期咱們要將這個view的翻頁效果以及動畫補齊github

本篇只着重於思路和實現步驟,裏面用到的一些知識原理不會很是細地拿來說,若是有不清楚的api或方法能夠在網上搜下相應的資料,確定有大神講得很是清楚的,我這就不獻醜了。本着認真負責的精神我會把相關知識的博文連接也貼出來(其實就是懶不想寫那麼多哈哈),你們能夠自行傳送。爲了照顧第一次閱讀系列博客的小夥伴,本篇會出現一些在以前系列博客就講過的內容,看過的童鞋自行跳過該段便可api

國際慣例,先上效果圖,本次主要補全了翻頁效果以及增長取消翻頁的動畫ide


完善右側最大翻頁距離的限制

開講以前,我先把標識點的位置圖貼出來讓你們回顧一下post

在上篇博客中咱們講了如何限制翻頁的最大距離,也就是c點的x座標不能小於0,雖然目的達到了,可是用戶體驗並很差,能夠很明顯地觀察到當c點x座標處於臨界值時,翻頁會靜止不動,若是此時觸摸點大範圍移動後,會出現翻頁「瞬移」,形成一種卡頓的感受,以下圖學習

要消除這種「瞬移」的現象,咱們要在c點x座標小於0的狀況下,讓c點強制處於臨界位置(左下角),而後翻頁頁角繼續跟隨觸摸點移動的方向移動,要作到這一點得用到一些類似三角形的數學知識,從新計算出a點的位置繪製View,先來看下實現的原理(請無視個人渣畫工╮(╯▽╰)╭ )動畫

圖中咱們將觸摸點標爲a1,與a1對應的c點標爲c1,此時c1的x座標是小於0。而a2是咱們從新計算獲得的a點,也就是最後進行繪製的a點,其對應的c點標爲c2c2位於View的左下角(x座標爲0),容易觀察到直角三角形a1 c1 m1直角三角形a2 c2 m2類似,此時f點位於View的右下角(在右上角同理),所以咱們能夠經過相應的公式計算獲得a2的座標爲(f.x-w2,f.y-h2),獲得計算a2的方法後,咱們修改原來的BookPageView

/** * 設置觸摸點 * @param x * @param y * @param style */
public void setTouchPoint(float x, float y, String style){
	switch (style){
		case STYLE_TOP_RIGHT:
			f.x = viewWidth;
			f.y = 0;
			break;
		case STYLE_LOWER_RIGHT:
			f.x = viewWidth;
			f.y = viewHeight;
			break;
		default:
			break;
	}
	a.x = x;
	a.y = y;
	calcPointsXY(a,f);

	MyPoint touchPoint = new MyPoint(x,y);
	if(calcPointCX(touchPoint,f)<0){//若是c點x座標小於0則從新測量a點座標
		calcPointAByTouchPoint();
		calcPointsXY(a,f);
	}
	postInvalidate();
}

/** * 若是c點x座標小於0,根據觸摸點從新測量a點座標 */
private void calcPointAByTouchPoint(){
	float w0 = viewWidth - c.x;

	float w1 = Math.abs(f.x - a.x);
	float w2 = viewWidth * w1 / w0;
	a.x = Math.abs(f.x - w2);

	float h1 = Math.abs(f.y - a.y);
	float h2 = w2 * h1 / w1;
	a.y = Math.abs(f.y - h2);
}
複製代碼

效果如圖


添加橫向翻頁效果

既然咱們實現的是仿真的翻頁效果,翻頁除了從上下兩角翻,天然還能橫向水平進行翻頁。咱們先將View劃分紅上下左右中五個區域,如圖

咱們根據觸摸起始的位置所位於的區域,定義五種不一樣的手勢操做,其中上下(top,low)對應的是上下角進行翻頁,左右(left,right)對應的橫向水平翻頁,中間(middle)則是爲了之後做爲呼出菜單而保留的區域。爲了提升代碼複用率和儘量小的改動,咱們實現橫向翻頁只需將a點的y座標強制等於View的高度減1便可(固然你們也能夠根據本身的須要從新計算橫向翻頁時的繪製區域,我這裏就簡單實現了),修改咱們的BookPageView

private String style;
public static final String STYLE_LEFT = "STYLE_LEFT";//點擊左邊區域
public static final String STYLE_RIGHT = "STYLE_RIGHT";//點擊右邊區域
public static final String STYLE_MIDDLE = "STYLE_MIDDLE";//點擊中間區域
public static final String STYLE_TOP_RIGHT = "STYLE_TOP_RIGHT";//f點在右上角
public static final String STYLE_LOWER_RIGHT = "STYLE_LOWER_RIGHT";//f點在右下角

/** * 設置觸摸點 * @param x * @param y * @param style */
public void setTouchPoint(float x, float y, String style){
	MyPoint touchPoint = new MyPoint();
	a.x = x;
	a.y = y;
	this.style = style;
	switch (style){
		case STYLE_TOP_RIGHT:
			f.x = viewWidth;
			f.y = 0;
			calcPointsXY(a,f);
			touchPoint = new MyPoint(x,y);
			if(calcPointCX(touchPoint,f)<0){//若是c點x座標小於0則從新測量a點座標
				calcPointAByTouchPoint();
				calcPointsXY(a,f);
			}
			postInvalidate();
			break;
		case STYLE_LEFT:
		case STYLE_RIGHT:
			a.y = viewHeight-1;
			f.x = viewWidth;
			f.y = viewHeight;
			calcPointsXY(a,f);
			postInvalidate();
			break;
		case STYLE_LOWER_RIGHT:
			f.x = viewWidth;
			f.y = viewHeight;
			calcPointsXY(a,f);
			touchPoint = new MyPoint(x,y);
			if(calcPointCX(touchPoint,f)<0){//若是c點x座標小於0則從新測量a點座標
				calcPointAByTouchPoint();
				calcPointsXY(a,f);
			}
			postInvalidate();
			break;
		default:
			break;
	}
}
複製代碼

在Activity中監聽觸摸操做

public class PageActivity extends AppCompatActivity {
    private BookPageView bookPageView;
    private String style = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_page);

        bookPageView = (BookPageView) findViewById(R.id.view_book_page);
        bookPageView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        float x = event.getX();
                        float y = event.getY();
                        float width = bookPageView.getViewWidth();
                        float height = bookPageView.getViewHeight();
                        if(x<=width/3){//左
                            style = bookPageView.STYLE_LEFT;
// Toast.makeText(PageActivity.this,"點擊了左部",Toast.LENGTH_SHORT).show();
                            bookPageView.setTouchPoint(x,y,style);

                        }else if(x>width/3 && y<=height/3){//上
                            style = bookPageView.STYLE_TOP_RIGHT;
// Toast.makeText(PageActivity.this,"點擊了上部",Toast.LENGTH_SHORT).show();
                            bookPageView.setTouchPoint(x,y,style);

                        }else if(x>width*2/3 && y>height/3 && y<=height*2/3){//右
                            style = bookPageView.STYLE_RIGHT;
// Toast.makeText(PageActivity.this,"點擊了右部",Toast.LENGTH_SHORT).show();
                            bookPageView.setTouchPoint(x,y,style);

                        }else if(x>width/3 && y>height*2/3){//下
                            style = bookPageView.STYLE_LOWER_RIGHT;
// Toast.makeText(PageActivity.this,"點擊了下部",Toast.LENGTH_SHORT).show();
                            bookPageView.setTouchPoint(x,y,style);

                        }else if(x>width/3 && x<width*2/3 && y>height/3 && y<height*2/3){//中
                            style = bookPageView.STYLE_MIDDLE;
// Toast.makeText(PageActivity.this,"點擊了中部",Toast.LENGTH_SHORT).show();
// bookPageView.setTouchPoint(x,y,bookPageView.STYLE_MIDDLE);
                        }
                        break;
                    case MotionEvent.ACTION_MOVE:
                        bookPageView.setTouchPoint(event.getX(),event.getY(),style);
                        break;
                    case MotionEvent.ACTION_UP:
                        bookPageView.setDefaultPath();
                        break;
                }
                return false;
            }
        });
    }
}
複製代碼

效果如圖


增長取消翻頁的動畫

android scroller類的使用

Android學習之 Scroller的介紹與使用

Android Scroller徹底解析,關於Scroller你所需知道的一切

Android -- Interpolator

android動畫 之Interpolator類

由於咱們還沒實現將書籍內容導入View中,因此咱們先來實現取消翻頁的動畫效果。這裏咱們結合ScrollerInterpolator插值器,實現當咱們手指離開屏幕時,a點能自動滑落到右下角(右上角)的效果,有關ScrollerInterpolator方面的知識,我將相關博客連接貼出來了,你們能夠相互對照着理解,我就不詳細闡述了。修改BookPageView

private Scroller mScroller;

private void init(Context context, @Nullable AttributeSet attrs){
	//省略部分代碼...
	mScroller = new Scroller(context,new LinearInterpolator());//以常量速率滑動便可
}

@Override
public void computeScroll() {
	if (mScroller.computeScrollOffset()) {
		float x = mScroller.getCurrX();
		float y = mScroller.getCurrY();
		
		if(style.equals(STYLE_TOP_RIGHT)){
			setTouchPoint(x,y,STYLE_TOP_RIGHT);
		}else {
			setTouchPoint(x,y,STYLE_LOWER_RIGHT);
		}
		if (mScroller.getFinalX() == x && mScroller.getFinalY() == y){
			setDefaultPath();//重置默認界面
		}
	}
}

/** * 取消翻頁動畫,計算滑動位置與時間 */
public void startCancelAnim(){
	int dx,dy;
	//讓a滑動到f點所在位置,留出1像素是爲了防止當a和f重疊時出現View閃爍的狀況
	if(style.equals(STYLE_TOP_RIGHT)){
		dx = (int) (viewWidth-1-a.x);
		dy = (int) (1-a.y);
	}else {
		dx = (int) (viewWidth-1-a.x);
		dy = (int) (viewHeight-1-a.y);
	}
	mScroller.startScroll((int) a.x, (int) a.y, dx, dy, 400);
}
複製代碼

在Activity中監聽手指擡起操做

case MotionEvent.ACTION_UP:
	bookPageView.startCancelAnim();
	break;
複製代碼

效果如圖

至此本篇教程就告一段落了,這期比較短,主要是對上期的補充。下期會實現書籍內容填充或者繪製陰影,看狀況吧๑乛◡乛๑。若是你們看了感受還不錯麻煩點個贊,大家的支持是我最大的動力~

相關文章
相關標籤/搜索