Android clipChildren與clipToPadding使用以及簡單ViewPager自定義切換效果
首先看看我們要實現的效果:
主要希望實現兩個效果:
1. 滾動的文字框在TITLE“下方“穿過,但初始時,文字框是有TITLE的高度的”paddingTop”的;
2. 下方第三個圖示的高度超出其所在的父控制元件高度。
先上佈局檔案:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height ="match_parent"
android:background="#f6f6f6"
android:clipChildren="false"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingTop="50dp">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height ="wrap_content"
android:text="很長很長的文字\n很長很長的文字\n很長很長的文字\n很長很長的文字\n很長很長的文字\n很長很長的文字\n很長很長的文字\n很長很長的文字\n很長很長的文字\n很長很長的文字\n很長很長的文字\n很長很長的文字\n很長很長的文字\n"
android:textSize="50sp"/>
</ScrollView>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#a00058f1"
android:gravity="center"
android:text="TITLE"
android:textColor="#ffffffff"
android:textSize="20sp"/>
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="bottom"
android:background="#fff"
android:elevation="12dp"
android:orientation="horizontal">
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@mipmap/ic_launcher"/>
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@mipmap/ic_launcher"/>
<ImageView
android:id="@+id/iv"
android:layout_width="0dp"
android:layout_height="180dp"
android:layout_gravity="bottom"
android:layout_weight="1"
android:scaleType="fitXY"
android:src="@mipmap/ic_launcher"/>
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@mipmap/ic_launcher"/>
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@mipmap/ic_launcher"/>
</LinearLayout>
</LinearLayout>
首先先引入兩個屬性:
1. android:clipChildren – 是否限制子檢視在其範圍內,簡單理解,就是其子view是否可以在超出自身原本的範圍繪製“突出”的部分,預設值為true。需要注意的是,突出的部分是沒有響應事件的,如下圖:
第三個圖示雖然超出了LinearLayout的高度範圍,但是點選超出的部分,是不會響應imageview的點選事件的。此屬性一般需要在根節點設定。
2. android:clipToPadding – 這個就能比較簡單理解了,是否允許子view在padding的範圍中繪製,預設值為true。一般設定此屬性為false,以實現如上圖所示的,ListView、RecycleView、ScrollView的“初始padding”的效果。
clipToPadding和clipChildren 還可以配合Viewpager,實現各種酷炫的切換效果,如下面的例子:
佈局檔案如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:id="@+id/fl"
android:clickable="true"
android:clipChildren="false"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_gravity="center"
android:layout_marginLeft="60dp"
android:layout_marginRight="60dp"
android:background="#f6f6f6"
android:clipToPadding="false"
android:orientation="vertical"
android:overScrollMode="never"
android:paddingBottom="20dp"
android:paddingTop="20dp"/>
</FrameLayout>
中間灰色的部分是ViewPager,要實現此效果,需要ViewPager的父容器設定clipChildren為false以及自身設定clipToPadding為false,同時設定左右margin,以顯示前後兩頁,同時需在程式碼中設定:
vp.setPageMargin(30); // 設定頁間的距離
vp.setOffscreenPageLimit(3); // 因為要同時顯示三頁,因此此處需要將預設的快取頁面從1變為3
vp.setPageTransformer(false, new PageAnimation()); // 自定義切換效果
vp.setAdapter(new Adapter());
其中,setPageTransformer是用來給ViewPager設定切換效果的,主要是重寫
/**
* page - Apply the transformation to this page
* position - Position of page relative to the current front-and-center position of the pager. 0 is front and center. 1 is one full page position to the right, and -1 is one page position to the left.
*/
public void transformPage(View page, float position)
方法,page就是ViewPager中的單個頁面,position指的是這個page在ViewPager中的當前位置。靜止時,
當前選中的(一般是中央的)position是0,左邊的是-1,右邊的是1,以此類推。在手指向左滑動過程中,當前選中的page的position從0變為-1,這期間的position都會回撥到這個方法,我們就可以利用這個做一系列的動畫了,以下是上例的切換效果:
/**
* 切換動畫
*/
class PageAnimation implements ViewPager.PageTransformer {
final float SCALE_MAX = 0.75f;
final float ALPHA_MAX = 0.5f;
final float MAX_Z = 12;
@Override
public void transformPage(View page, float position) {
float scale = (position < 0)
? ((1 - SCALE_MAX) * position + 1)
: ((SCALE_MAX - 1) * position + 1);
float alpha = (position < 0)
? ((1 - ALPHA_MAX) * position + 1)
: ((ALPHA_MAX - 1) * position + 1);
//為了滑動過程中,page間距不變,這裡做了處理
if (position < 0) {
ViewCompat.setPivotX(page, page.getWidth());
ViewCompat.setPivotY(page, page.getHeight() / 2);
} else {
ViewCompat.setPivotX(page, 0);
ViewCompat.setPivotY(page, page.getHeight() / 2);
}
ViewCompat.setScaleX(page, scale);
ViewCompat.setScaleY(page, scale);
ViewCompat.setAlpha(page, Math.abs(alpha));
// 陰影
ViewCompat.setElevation(page, MAX_Z * Math.abs(alpha));
}
}
完整程式碼可參見此處