Android 自定義實(shí)現(xiàn)翻轉(zhuǎn)卡片的View
來源:程序員人生 發(fā)布時間:2015-04-14 08:50:53 閱讀次數(shù):2532次
1般1個View只有1面,但是可以自定義1個View,實(shí)現(xiàn)像翻書那樣的翻轉(zhuǎn)效果。
旋轉(zhuǎn)View:
/**
* 兩種方式構(gòu)造1個翻轉(zhuǎn)卡片
* 1:直接提供1個特定命名格式的View
* 2:提供兩個線性布局(正面和,反面)
* Created by lip on 2015/4/8.
*/
public class FlipView extends LinearLayout implements View.OnClickListener,RotateAnimation.InterpolatedTimeListener
{
private LinearLayout m_first_ll, m_second_ll;
private boolean enableRefresh;
private LinearLayout view;
private View clickView;//當(dāng)前的view
private Context context;
public FlipView(Context context)
{
super(context);
this.context=context;
//initViews();
}
public FlipView(Context context,AttributeSet attrs)
{
super(context,attrs);
this.context=context;
//initViews();
}
/**
*/
public void initViews()
{
view=(LinearLayout)inflate(context,R.layout.flip_view,null);
m_first_ll=(LinearLayout)view.findViewById(R.id.first_ll);
m_second_ll=(LinearLayout)view.findViewById(R.id.second_ll);
m_first_ll.setOnClickListener(this);
m_second_ll.setOnClickListener(this);
addView(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
/**
* @param ll1 正面
* @param ll2 反面
*/
public void addViews(LinearLayout ll1,LinearLayout ll2)
{
m_first_ll=ll1;
m_second_ll=ll2;
m_first_ll.setOnClickListener(this);
m_second_ll.setOnClickListener(this);
addView(m_first_ll, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
addView(m_second_ll, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
/**
* flag=0 翻到正面
* flag=1 翻到反面
* @param flag
*/
public void show(int flag)
{
enableRefresh = true;
RotateAnimation rotateAnim = null;
float cX = this.getWidth() / 2.0f;
float cY = this.getHeight() / 2.0f;
if(flag==0)
rotateAnim = new RotateAnimation(cX, cY,
RotateAnimation.ROTATE_DECREASE);
else if(flag==1)
rotateAnim = new RotateAnimation(cX, cY,
RotateAnimation.ROTATE_INCREASE);
if (rotateAnim != null) {
rotateAnim.setInterpolatedTimeListener(this);
rotateAnim.setFillAfter(true);
this.startAnimation(rotateAnim);
}
}
@Override
public void onClick(View v) {
Log.d("click:",v.toString());
enableRefresh = true;
clickView=v;
RotateAnimation rotateAnim = null;
float cX = this.getWidth() / 2.0f;
float cY = this.getHeight() / 2.0f;
if (m_first_ll==v) {
rotateAnim = new RotateAnimation(cX, cY,
RotateAnimation.ROTATE_INCREASE);
} else if (m_second_ll == v) {
rotateAnim = new RotateAnimation(cX, cY,
RotateAnimation.ROTATE_DECREASE);
}
if (rotateAnim != null) {
rotateAnim.setInterpolatedTimeListener(this);
rotateAnim.setFillAfter(true);
this.startAnimation(rotateAnim);
}
}
@Override
public void interpolatedTime(float interpolatedTime) {
if (enableRefresh && interpolatedTime > 0.5f) {
setHint();
enableRefresh = false;
}
}
public void setHint() {
if (clickView == m_first_ll) {
m_first_ll.setVisibility(View.GONE);
m_second_ll.setVisibility(View.VISIBLE);
} else if (clickView==m_second_ll) {
m_second_ll.setVisibility(View.GONE);
m_first_ll.setVisibility(View.VISIBLE);
}
}
}
來看看使用方法:
public class FlipActivity extends Activity
{
private FlipView flipView;
LinearLayout firstLL,secondLL;
LinearLayout root;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_flip);
initViews();
}
private void initViews()
{
root=(LinearLayout)LayoutInflater.from(this).inflate(R.layout.activity_flip,null);
flipView=(FlipView)root.findViewById(R.id.flip_view);
/*********第1種方式(要主動調(diào)用initViews)*************/
// firstLL=(LinearLayout)LayoutInflater.from(this).inflate(R.layout.flip_view1,null);
// secondLL=(LinearLayout)LayoutInflater.from(this).inflate(R.layout.flip_view2,null);
/*********第2種方式*************/
firstLL=(LinearLayout)root.findViewById(R.id.root_ll1);
secondLL=(LinearLayout)root.findViewById(R.id.root_ll2);
root.removeView(firstLL);
root.removeView(secondLL);
flipView.addViews(firstLL,secondLL);
setContentView(root);
}
}
既然1個View 有兩面,那固然需要主動去設(shè)置正面和反面的內(nèi)容了。
flipView.addViews(firstLL,secondLL);第1個參數(shù)就是正面的view,第2個參數(shù)是反面的view,這兩個view都是線性布局。我提供了兩種設(shè)置正反面的的方式,如果要是對布局有1點(diǎn)了解,其實(shí)這是1樣的
</pre><p> 旋轉(zhuǎn)工具類(網(wǎng)上參考他人的):</p><p> <pre name="code" class="java">public class RotateAnimation extends Animation {
/** 值為true時可明確查看動畫的旋轉(zhuǎn)方向。 */
public static final boolean DEBUG = false;
/** 沿Y軸正方向看,數(shù)值減1時動畫逆時針旋轉(zhuǎn)。 */
public static final boolean ROTATE_DECREASE = true;
/** 沿Y軸正方向看,數(shù)值減1時動畫順時針旋轉(zhuǎn)。 */
public static final boolean ROTATE_INCREASE = false;
/** Z軸上最大深度。 */
public static final float DEPTH_Z = 310.0f;
/** 動畫顯示時長。 */
public static final long DURATION = 800l;
/** 圖片翻轉(zhuǎn)類型。 */
private final boolean type;
private final float centerX;
private final float centerY;
private Camera camera;
public RotateAnimation(float cX, float cY, boolean type) {
centerX = cX;
centerY = cY;
this.type = type;
// 設(shè)置動畫時長
setDuration(DURATION);
}
@Override
public void initialize(int width, int height, int parentWidth,
int parentHeight) {
// 在構(gòu)造函數(shù)以后、applyTransformation()之前調(diào)用本方法。
super.initialize(width, height, parentWidth, parentHeight);
camera = new Camera();
}
@Override
protected void applyTransformation(float interpolatedTime,
Transformation transformation) {
// interpolatedTime:動畫進(jìn)度值,范圍為0~1,0.5為正好翻轉(zhuǎn)1半
if (listener != null) {
listener.interpolatedTime(interpolatedTime);
}
float from = 0.0f, to = 0.0f;
if (type == ROTATE_DECREASE) {
from = 0.0f;
to = 180.0f;
} else if (type == ROTATE_INCREASE) {
from = 360.0f;
to = 180.0f;
}
// 旋轉(zhuǎn)的角度
float degree = from + (to - from) * interpolatedTime;
boolean overHalf = (interpolatedTime > 0.5f);
if (overHalf) {
// 翻轉(zhuǎn)過半的情況下,為保證數(shù)字仍為可讀的文字而非鏡面效果的文字,需翻轉(zhuǎn)180度。
degree = degree - 180;
}
// 旋轉(zhuǎn)深度
float depth = (0.5f - Math.abs(interpolatedTime - 0.5f)) * DEPTH_Z;
final Matrix matrix = transformation.getMatrix();
camera.save();
// 深度――》相當(dāng)于與屏幕的距離
camera.translate(0.0f, 0.0f, depth);
// 以x軸旋轉(zhuǎn)
// camera.rotateX(degree);
// 以y軸旋轉(zhuǎn)
camera.rotateY(degree);
camera.getMatrix(matrix);
camera.restore();
if (DEBUG) {
if (overHalf) {
matrix.preTranslate(-centerX * 2, -centerY);
matrix.postTranslate(centerX * 2, centerY);
}
} else {
// 確保圖片的翻轉(zhuǎn)進(jìn)程1直處于組件的中心點(diǎn)位置
/*
* preTranslate是指在setScale前平移,postTranslate是指在setScale后平移,它們參數(shù)是平移的距離,
* 而不是平移目的地的坐標(biāo)!
* 由于縮放是以(0,0)為中心的,所以為了把界面的中心與(0,0)對齊,就要preTranslate(-centerX,
* -centerY),setScale完成后, 調(diào)用postTranslate(centerX,
* centerY),再把圖片移回來,這樣看到的動畫效果就是activity的界面圖片從中心不停的縮放了
* 注:centerX和centerY是界面中心的坐標(biāo)
*/
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}
/** 用于監(jiān)聽動畫進(jìn)度。當(dāng)值過半時需更新的內(nèi)容。 */
private InterpolatedTimeListener listener;
public void setInterpolatedTimeListener(InterpolatedTimeListener listener) {
this.listener = listener;
}
/** 動畫進(jìn)度監(jiān)聽器。 */
public static interface InterpolatedTimeListener {
public void interpolatedTime(float interpolatedTime);
}
}
xml布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<cn.xindrace.viewflip.FlipView
android:id="@+id/flip_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:id="@+id/root_ll1"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="It is the first side"/>
</LinearLayout>
<LinearLayout
android:id="@+id/root_ll2"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="It is the first side"/>
</LinearLayout>
</LinearLayout>
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈