Android例項(一)—— 3D畫廊
3D畫廊
之前我都是寫的學習的內容,我在寫這些教程時遇到有趣的炫酷的小例子也會專門拿出來寫一篇文章,今天就寫一個酷炫的小例子,叫3D畫廊,它是屬於ViewPage的進階版。
下面的指示器是使用的一大神的第三方庫,會在文章下方簡單講述一下。
效果圖
3D畫廊的實現
首先是佈局檔案
1 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="match_parent" 3 android:layout_height="match_parent"4 xmlns:app="http://schemas.android.com/apk/res-auto" 5 android:clipChildren="false" 6 android:background="@android:color/black" 7 android:id="@+id/frame_layout"> 8 9 <android.support.v4.view.ViewPager 10 android:layout_width="match_parent" 11 android:layout_height="450dp" 12 android:layout_gravity="center" 13 android:id="@+id/gallery" 14 android:clipChildren="false" 15 android:layout_marginLeft="85dp" 16 android:layout_marginRight="85dp" /> 17 18 <com.lwj.widget.viewpagerindicator.ViewPagerIndicator 19 android:id="@+id/indicator_circle_line" 20 android:layout_width="match_parent" 21 android:layout_height="50dp" 22 android:layout_gravity="bottom" 23 android:background="#efefef" 24 app:vpi_default_color="#FF239AF5" 25 app:vpi_distance="60dp" 26 app:vpi_distanceType="BY_LAYOUT" 27 app:vpi_indicatorType="CIRCLE_LINE" 28 app:vpi_radius="10dp" 29 app:vpi_selected_color="#FF239AF5" 30 /> 31 32 </FrameLayout>
程式碼中的ViewPagerIndicator是用於實現下方的指示器,這個我們在最後在進行解釋;
首先佈局使用幀佈局,內部用到ViewPager控制元件,注意在ViewPager控制元件的父佈局中我們要新增android:clipChildren="false"屬性,它的作用是定義它的子控制元件是否要在它應有的邊界內進行繪製,預設值為true。我們這裡要用false。
然後在ViewPager中用到android:layout_marginLeft和android:layout_marginRight屬性,值不能太大,過大會導致看不到兩邊的影象,具體根據自己滿意進行調整。高度屬性為圖片和倒影的加起來的高度,自己進行調整。
GalleryPageTransformer類
1 package sample.sdk.qy.com.demo; 2 3 import android.support.v4.view.ViewPager; 4 import android.view.View; 5 6 public class GalleryPageTransformer implements ViewPager.PageTransformer { 7 private static final float MAX_ROTATION=20.0f; 8 private static final float MIN_SCALE=0.75f; 9 private static final float MAX_TRANSLATE=20.0f; 10 11 @Override 12 public void transformPage(View page, float position) { 13 if(position<-1) { 14 page.setTranslationX(MAX_TRANSLATE); 15 page.setScaleX(MIN_SCALE); 16 page.setScaleY(MIN_SCALE); 17 page.setRotationY(-MAX_ROTATION); 18 } 19 else if(position<=0) { 20 page.setTranslationX(-MAX_TRANSLATE*position); 21 float scale=MIN_SCALE+(1-MIN_SCALE)*(1.0f+position); 22 page.setScaleX(scale); 23 page.setScaleY(scale); 24 page.setRotationY(MAX_ROTATION*position); 25 } 26 else if(position<=1) { 27 page.setTranslationX(-MAX_TRANSLATE*position); 28 float scale=MIN_SCALE+(1-MIN_SCALE)*(1.0f-position); 29 page.setScaleX(scale); 30 page.setScaleY(scale); 31 page.setRotationY(MAX_ROTATION*position); 32 } 33 else { 34 page.setTranslationX(-MAX_TRANSLATE); 35 page.setScaleX(MIN_SCALE); 36 page.setScaleY(MIN_SCALE); 37 page.setRotationY(MAX_ROTATION); 38 } 39 } 40 }
PageTransformer是ViewPager內部定義的介面,這個介面主要用於控制ViewPager中item view的滑動效果。
- setTranslationX 設定view相對原始位置的水平偏移量
- setScaleX 設定水平縮放的基準點
- setScaleY 設定豎直縮放的基準點
- setRotationY 設定豎直的選擇的基準點
ImageUtils類
1 package sample.sdk.qy.com.demo; 2 3 import android.content.Context; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 import android.graphics.Canvas; 7 import android.graphics.Color; 8 import android.graphics.LinearGradient; 9 import android.graphics.Matrix; 10 import android.graphics.Paint; 11 import android.graphics.PorterDuff; 12 import android.graphics.PorterDuffXfermode; 13 import android.graphics.Shader; 14 15 public class ImageUtils { 16 public static Bitmap getReverseBitmapById(Context context, int resId, float percent) { 17 // get the source bitmap 18 Bitmap srcBitmap= BitmapFactory.decodeResource(context.getResources(), resId); 19 // get the tow third segment of the reverse bitmap 20 Matrix matrix=new Matrix(); 21 matrix.setScale(1, -1); 22 Bitmap rvsBitmap=Bitmap.createBitmap(srcBitmap, 0, (int) (srcBitmap.getHeight()*(1-percent)), 23 srcBitmap.getWidth(), (int) (srcBitmap.getHeight()*percent), matrix, false); 24 // combine the source bitmap and the reverse bitmap 25 Bitmap comBitmap=Bitmap.createBitmap(srcBitmap.getWidth(), 26 srcBitmap.getHeight()+rvsBitmap.getHeight()+20, srcBitmap.getConfig()); 27 Canvas gCanvas=new Canvas(comBitmap); 28 gCanvas.drawBitmap(srcBitmap, 0, 0, null); 29 gCanvas.drawBitmap(rvsBitmap, 0, srcBitmap.getHeight()+20, null); 30 Paint paint=new Paint(); 31 LinearGradient shader=new LinearGradient(0, srcBitmap.getHeight()+20, 0, comBitmap.getHeight(), 32 Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP); 33 paint.setShader(shader); 34 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); 35 gCanvas.drawRect(0, srcBitmap.getHeight()+20, srcBitmap.getWidth(), comBitmap.getHeight(), paint); 36 return comBitmap; 37 } 38 }
這是做圖片倒影的方法,內部使用了Canvas和Bitmap類,這些後面會進行講述。
ViewAdapter類
1 package sample.sdk.qy.com.demo; 2 3 import android.support.v4.view.PagerAdapter; 4 import android.view.View; 5 import android.view.ViewGroup; 6 7 import java.util.List; 8 9 public class ViewAdapter extends PagerAdapter { 10 private List<View> datas; 11 12 public ViewAdapter(List<View> list) { 13 datas=list; 14 } 15 16 @Override 17 public int getCount() { 18 return datas.size(); 19 } 20 21 @Override 22 public boolean isViewFromObject(View view, Object object) { 23 return view==object; 24 } 25 26 @Override 27 public Object instantiateItem(ViewGroup container, int position) { 28 View view=datas.get(position); 29 container.addView(view); 30 return view; 31 } 32 33 @Override 34 public void destroyItem(ViewGroup container, int position, Object object) { 35 container.removeView(datas.get(position)); 36 } 37 }
介面卡類,這裡的適配方式為圖片和倒影一同進行適配。
MainActivity類
1 package sample.sdk.qy.com.demo; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.support.v4.view.PagerAdapter; 6 import android.support.v4.view.ViewPager; 7 import android.view.MotionEvent; 8 import android.view.View; 9 import android.widget.FrameLayout; 10 import android.widget.ImageView; 11 12 import com.lwj.widget.viewpagerindicator.ViewPagerIndicator; 13 14 import java.lang.reflect.Field; 15 import java.util.ArrayList; 16 import java.util.List; 17 18 public class MainActivity extends Activity { 19 20 private List<View> pages; 21 private FrameLayout layout; 22 private ViewPager pager; 23 private ViewPagerIndicator mIndicatorCircleLine; 24 25 @Override 26 protected void onCreate(Bundle savedInstanceState) { 27 super.onCreate(savedInstanceState); 28 setContentView(R.layout.activity_main); 29 30 pages=getPages(); 31 pager=(ViewPager) findViewById(R.id.gallery); 32 PagerAdapter adapter=new ViewAdapter(pages); 33 pager.setAdapter(adapter); 34 pager.setPageMargin(20); 35 pager.setOffscreenPageLimit(3); 36 pager.setPageTransformer(true, new GalleryPageTransformer()); 37 38 layout=(FrameLayout) findViewById(R.id.frame_layout); 39 layout.setOnTouchListener(new View.OnTouchListener() { 40 @Override 41 public boolean onTouch(View v, MotionEvent event) { 42 return pager.dispatchTouchEvent(event); 43 } 44 }); 45 46 mIndicatorCircleLine = (ViewPagerIndicator) findViewById(R.id.indicator_circle_line); 47 mIndicatorCircleLine.setViewPager(pager,9); 48 } 49 50 private List<View> getPages() { 51 List<View> pages=new ArrayList<>(); 52 Field[] fields=R.drawable.class.getDeclaredFields(); 53 try { 54 for (Field field : fields) { 55 if (field.getName().startsWith("page")) { 56 ImageView view = new ImageView(this); 57 view.setImageBitmap(ImageUtils.getReverseBitmapById(this, field.getInt(null), 0.5f)); 58 pages.add(view); 59 } 60 } 61 } catch (IllegalAccessException e) { 62 e.printStackTrace(); 63 } 64 return pages; 65 } 66 }
主介面方法,主要用於填充入圖片、介面卡適配。這裡填充圖片的方法為在drawable檔案中查詢以page開頭的圖片進行填充。
到這裡3D畫廊就完成了。。。。。。。。。
指示器
下面來說一下指示器的做法,用的是網上一大神的第三方類。
使用方法:
1、在 project的build.gradle 新增:
allprojects { repositories { ... maven { url "https://jitpack.io" } } }
2、在module的build.gradle 新增:
dependencies {
implementation 'com.github.LinweiJ:ViewPagerIndicator:0.1.0' }
注意這裡要用implementation,compile現在已被廢棄,官方顯示將在2018年年底刪除。
3、將ViewPagerIndicator控制元件新增到佈局檔案。
屬性:
app:vpi_selected_color
app:vpi_default_color
(如果 indicatorType=CIRCLE_LINE default_color 為指示器唯一顏色 ,selected_color 不起作用)app:vpi_radius
(點的大小,在indicatorType= CIRCLE_LINE 的情況下 radius 是點的高)app:vpi_length
(只作用在 indicatorType=CIRCLE_LINE 的情況下,為 指示器點的長度)app:vpi_distance
(只作用在 distanceType=BY_DISTANCE 的情況下)app:vpi_num
app:vpi_indicatorType
(LINE; CIRCLE; CIRCLE_LINE; BEZIER;SPRING)LINE:線 ; CIRCLE:圓點(預設) ; CIRCLE_LINE:圓角矩形; BEZIER:彈性球 ; SPRING: 彈簧粘性球app:vpi_distanceType
(BY_RADIUS; BY_DISTANCE ; BY_LAYOUT )BY_RADIUS:3倍radius ; BY_DISTANCE :定義固定距離 ;BY_LAYOUT :根據layout_width均分得到距離app:vpi_animation
(預設為true:動畫開啟 ; false:關閉動畫)
4、在java檔案中初始化該控制元件
使用mIndicatorCircleLine.setViewPager(pager,9);,第一個引數為介面卡,第二個引數為圖片的個數。