Android自定義元件系列【11】——實現3D立體旋轉效果
package com.example.rotation3dview; import android.content.Context; import android.graphics.Camera; import android.graphics.Canvas; import android.graphics.Matrix; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewDebug.HierarchyTraceType; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.Scroller; public class Rote3DView extends ViewGroup{ private int mCurScreen = 1; // 滑動的速度 private static final int SNAP_VELOCITY = 500; private VelocityTracker mVelocityTracker; private int mWidth; private Scroller mScroller; private Camera mCamera; private Matrix mMatrix; // 旋轉的角度,可以進行修改來觀察效果 private float angle = 90; public Rote3DView(Context context, AttributeSet attrs) { super(context, attrs); mScroller = new Scroller(context); mCamera = new Camera(); mMatrix = new Matrix(); initScreens(); } public void initScreens(){ ViewGroup.LayoutParams p = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT); for (int i = 0; i < 3; i++) { this.addView(new ImageView(this.getContext()), i, p); } ((ImageView)this.getChildAt(0)).setImageResource(R.drawable.page1); ((ImageView)this.getChildAt(1)).setImageResource(R.drawable.page2); ((ImageView)this.getChildAt(2)).setImageResource(R.drawable.page3); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childLeft = 0; final int childCount = getChildCount(); for(int i = 0; i< childCount; i++){ final View childView = getChildAt(i); if(childView.getVisibility() != View.GONE){ final int childWidth = childView.getMeasuredWidth(); childView.layout(childLeft, 0, childLeft + childWidth, childView.getMeasuredHeight()); childLeft += childWidth; } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); final int width = MeasureSpec.getSize(widthMeasureSpec); final int widthMode = MeasureSpec.getMode(widthMeasureSpec); if(widthMode != MeasureSpec.EXACTLY){ throw new IllegalStateException("僅支援精確尺寸"); } final int heightMode = MeasureSpec.getMode(heightMeasureSpec); if(heightMode != MeasureSpec.EXACTLY){ throw new IllegalStateException("僅支援精確尺寸"); } final int count = getChildCount(); for(int i = 0; i < count; i++){ getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); } scrollTo(mCurScreen * width, 0); } private float mDownX; @Override public boolean onTouchEvent(MotionEvent event) { if(mVelocityTracker == null){ mVelocityTracker = VelocityTracker.obtain(); } //將當前的觸控事件傳遞給VelocityTracker物件 mVelocityTracker.addMovement(event); float x = event.getX(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if(!mScroller.isFinished()){ mScroller.abortAnimation(); } mDownX = x; break; case MotionEvent.ACTION_MOVE: int disX = (int)(mDownX - x); mDownX = x; scrollBy(disX, 0); break; case MotionEvent.ACTION_UP: final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000); int velocityX = (int) velocityTracker.getXVelocity(); if(velocityX > SNAP_VELOCITY && mCurScreen > 0){ snapToScreen(mCurScreen - 1); }else if(velocityX < -SNAP_VELOCITY && mCurScreen < getChildCount() - 1){ snapToScreen(mCurScreen + 1); }else{ snapToDestination(); } if(mVelocityTracker != null){ mVelocityTracker.recycle(); mVelocityTracker = null; } break; } return true; } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } } public void snapToDestination(){ setMWidth(); final int destScreen = (getScrollX() + mWidth / 2) / mWidth; snapToScreen(destScreen); } public void snapToScreen(int whichScreen){ whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); setMWidth(); int scrollX = getScrollX(); int startWidth = whichScreen * mWidth; if(scrollX != startWidth){ int delta = 0; int startX = 0; if(whichScreen > mCurScreen){ setPre(); delta = startWidth - scrollX; startX = mWidth - startWidth + scrollX; }else if(whichScreen < mCurScreen){ setNext(); delta = -scrollX; startX = scrollX + mWidth; }else{ startX = scrollX; delta = startWidth - scrollX; } mScroller.startScroll(startX, 0, delta, 0, Math.abs(delta) * 2); invalidate(); } } private void setNext(){ int count = this.getChildCount(); View view = getChildAt(count - 1); removeViewAt(count - 1); addView(view, 0); } private void setPre(){ int count = this.getChildCount(); View view = getChildAt(0); removeViewAt(0); addView(view, count - 1); } private void setMWidth(){ if(mWidth == 0){ mWidth = getWidth(); } } }
實現立體效果
新增如下程式碼:相關推薦
Android自定義元件系列【11】——實現3D立體旋轉效果
package com.example.rotation3dview; import android.content.Context; import android.graphics.Camera; import android.graphics.Canvas; import android.graphic
Android自定義元件系列【2】——Scroller類
在上一篇中介紹了View類的scrollTo和scrollBy兩個方法,對這兩個方法不太瞭解的朋友可以先看《自定義View及ViewGroup》scrollTo和scrollBy雖然實現了檢視的偏移,但是卻沒有更好的控制移動過程,移動是瞬間進行的。Scroller類就是為解決
百度分享怎麽 自定義圖片分享 【原創】
多功能 有道 amp popu har dia 1.0 例如 IV 我們在應用百度分享插件的時候, 默認如果開啟圖片分享的話,連很多小圖標也分享了,實在惱火! 去掉圖片分享吧,分享效果又不好。。。 如何做到自定義圖片分享呢? 就是預先定義tag標簽 例如: "tag":
Android 自定義View 系列文章目錄 Canvas篇
一、基礎 Android 畫筆 Paint 基本操作API:https://blog.csdn.net/huangliniqng/article/details/82588824 Android 畫布 Canvas 基本操作API:https://blog.csdn.net/
Android自定義View系列:標籤LabelView實戰篇
前言部分 本文主要介紹如何自定義一個常見的labels標籤,功能上主要支援,單選、多選、點選三種模式。因為這個使用率很高,並且這個是比較典型學習自定義ViewGroup的例子,所以特意動手實踐,加深對Android的認識。這個專案主要是為了自己學習使用,所以並不是很完善,先上一個效果
Android自定義元件(四)
1.陰影 陰影即可以為文字和圖形指定陰影,預設情況下,我們的文字和圖形都是繪製在主層(main layer)上,我們也可以將內容繪製到新的layer上,實際上陰影就是在main layer的下面添加了一個陰影層。 Paint類為此定義了一個名為setShadowLayer
循序漸進學.Net Core Web Api開發系列【11】:依賴注入
系列目錄 一、概述 本篇介紹如何採用依賴注入的方式建立和使用物件,主要從應用層面進行描述,不涉及具體的內部原理。 二、演練 假設要做一個日誌服務的類,它實現在控制檯打印出帶時間資訊的日誌資訊。 首先定義該服務的介面與實現類。 public interface ILogSe
【Qt】Qt之自定義搜尋框【轉】
簡述 關於搜尋框,大家都經常接觸。例如:瀏覽器搜尋、Windows資源管理器搜尋等。 當然,這些對於Qt實現來說毫無壓力,只要思路清晰,分分鐘搞定。 簡述 效果 細節分析 原始碼下載 效果 細節分析 實現細節需要如下步驟: 組合實現,輸入框+
Android自定義元件之日曆控制元件-精美日曆實現(內容、樣式可擴充套件)
需求 我們知道,Android系統本身有自帶的日曆控制元件,網路上也有很多開源的日曆控制元件資源,但是這些日曆控制元件往往樣式較單一,API較多,不易於在實際專案中擴充套件並實現出符合具體樣式風格的,內容可定製的效果。本文通過自定義日曆控制元件,實現了在內容和樣
Android自定義元件之美化radiobutton
其實美化方法很簡單隻需重寫ondraw方法是替換圖片即可 下面是原始碼 package com.myradio; import android.content.Context; import android.graphics.Canvas; import an
Android自定義佈局系列之一:流式佈局(含TextView的點選事件)
前言: 之前寫了Unity優化方面的文章,之後就沒寫了。之後想把C盤擴大點,室友試了分割槽助手,很好用,也成功了,我心動也試了下,以為不會出什麼意外,更不會出現資料丟失,抱著僥倖的心理沒臨時備份,哎!沒想到最重要的E盤(所有資料)裡所有資料都丟失了,之後用了資料恢復,
「HTML+CSS」--自定義按鈕樣式【001】
# 前言 > Hello!小夥伴! > 首先非常感謝您閱讀海轟的文章,倘若文中有錯誤的地方,歡迎您指出~ > 哈哈 自我介紹一下 > 暱稱:海轟 > 標籤:程式猿一隻|C++選手|學生 > 簡介:因C語言結識程式設計,隨後轉入計算機專業,有幸拿過國獎、省獎等,已保研。目前正在學習C++/Linux(真的真的
「HTML+CSS」--自定義按鈕樣式【002】
# 前言 > Hello!小夥伴! > 首先非常感謝您閱讀海轟的文章,倘若文中有錯誤的地方,歡迎您指出~ > 哈哈 自我介紹一下 > 暱稱:海轟 > 標籤:程式猿一隻|C++選手|學生 > 簡介:因C語言結識程式設計,隨後轉入計算機專業,有幸拿過國獎、省獎等,已保研。目前正在學習C++/Linux(真的真的
「HTML+CSS」--自定義按鈕樣式【003】
# 前言 > Hello!小夥伴! > 首先非常感謝您閱讀海轟的文章,倘若文中有錯誤的地方,歡迎您指出~ > 哈哈 自我介紹一下 > 暱稱:海轟 > 標籤:程式猿一隻|C++選手|學生 > 簡介:因C語言結識程式設計,隨後轉入計算機專業,有幸拿過國獎、省獎等,已保研。目前正在學習C++/Linux(真的真的
「HTML+CSS」--自定義按鈕樣式【004】
# 前言 > Hello!小夥伴! > 首先非常感謝您閱讀海轟的文章,倘若文中有錯誤的地方,歡迎您指出~ > 哈哈 自我介紹一下 > 暱稱:海轟 > 標籤:程式猿一隻|C++選手|學生 > 簡介:因C語言結識程式設計,隨後轉入計算機專業,有幸拿過國獎、省獎等,已保研。目前正在學習C++/Linux(真的真的
Android 自定義View-----流式佈局(粗糙實現)
//首先檢視一下佈局介面吧 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app
自定義view系列(5)--99.99%實現QQ側滑刪除效果
首先宣告本文是基於GitHub上"baoyongzhang"的SwipeMenuListView修改而來, 可以說這個側滑刪除效果是我見過效果最好且比較靈活的專案,沒有之一!!! 但是在使用它之前需要給大家提兩點注意事項: 1,該專案支援Gradle dependence
Android自定義View之導航欄(Fragment實現)
安卓輕量級底部導航欄 目前安卓開發中常常會用到底部導航欄這個控制元件,但是自己從零開始做一個又太麻煩。因此,我封裝了一個底部導航欄,同時,也做了一些修改,用於頂部也十分合適。下面是示例圖: 使用方法: 1.新增依賴 首先,在build.gradle檔案下加入 maven
Android自定義View——貝塞爾曲線實現水波紋進度球
效果圖 原理分析 首先需要了解的水波紋實現效果,可以在部落格的自定義View專題找到,其實現原理如下 利用貝塞爾曲線繪製螢幕外和螢幕內的sin曲線 利用path將sin曲線的左下角和右下角連線起來成為一塊區域 通過不斷的平移sin曲線,然後平移完
android自定義View(2):實現百分比自適應佈局
android介面適配難是歷史原因,我們只能想辦法解決。github上面已有一些佈局自適應的解決方案,今天我分享的是自定義控制元件:RelativieLayout自適應百分比寬高。直接上菜。 一,實現的效果圖 眼見為實,截圖所示,寬高都是50%,實現了自