編輯:關於Android編程
Android動畫有3類:幀動畫、視圖動畫、屬性動畫。幀動畫和視圖動畫又統稱為補間動畫。Android 3.0(API LEVEL 11)開始支持屬性動畫。
幀動畫是針對Drawable資源的動畫。其本質是一系列Drawable資源的連續變化,其本質是AnimationDrawable對象。其使用方法如下:
資源中用到了表示天氣的三張圖片
-
-
-
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
ImageView sampleIv= (ImageView)findViewById(R.id.iv_sample);
sampleIv.setBackgroundResource(R.drawable.wether_list);
final AnimationDrawable animationDrawable = (AnimationDrawable)sampleIv.getBackground();
sampleIv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animationDrawable.start();
}
});
}
點擊圖片之後就會連續變換不同的圖片出來
視圖動畫是對視圖控件(View)應用動畫,其本質是連續修改View的屬性來展現變化。主要有Scale,Rotate,Translate,Alpha。使用方法如下:
旋轉動畫
透明度動畫
位移動畫
組合動畫
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
final ImageView sampleIv= (ImageView)findViewById(R.id.iv_sample);
final Animation animation = AnimationUtils.loadAnimation(this,R.anim.roate360);
animation.setDuration(1500);
animation.setInterpolator(this,android.R.anim.linear_interpolator);
animation.setRepeatCount(Animation.INFINITE);
sampleIv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sampleIv.startAnimation(animation);
}
});
}
接下來重點講屬性動畫。
屬性動畫不僅僅針對視圖(View),它幾乎可以應用到任何對象。你可以定義屬性動畫來改變任意對象的屬性,不管這個對象是否會在屏幕上呈現出來。屬性動畫的本質是在一定時間段內連續地改變對象的屬性。
showView.setAlpha(0f);
showView.setVisibility(View.VISIBLE);
showView.animate()
.alpha(1f)
.setDuration(300/*ms*/)
.setListener(null);
hideView.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
hideView.setVisibility(View.GONE);
}
});
下面展示如何在切換Fragmeng時應用翻轉動畫
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_card_flip);
if (savedInstanceState == null) {
// 如果沒有實例,則將CardFrontFragment添加到Activity
//否則表明之前已經添加Fragment了
getFragmentManager()
.beginTransaction()
.add(R.id.container, new CardFrontFragment())
.commit();
} else {
mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);
}
// 監控返回棧的變化,以便正確地顯示操作圖標
getFragmentManager().addOnBackStackChangedListener(this);
}
@Override
public void onBackStackChanged() {
mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);
// 當返回棧發生變化,更新菜單顯示
invalidateOptionsMenu();
}
private void flipCard() {
//如果返回棧中有實例,直接返回當前一個Fragment
if (mShowingBack) {
getFragmentManager().popBackStack();
return;
}
//指示可以返回上一個Fragment
mShowingBack = true;
//添加CarBackFragment
getFragmentManager()
.beginTransaction()
// 自定義Frameng切換時的動畫
//包括切換當當前Fragment和返回到上一個Fragment的動畫
//這樣當按返回按鈕時也會有動畫效果
.setCustomAnimations(
R.animator.card_flip_right_in/*enter*/, R.animator.card_flip_right_out/*exit*/,
R.animator.card_flip_left_in/*popEnter*/, R.animator.card_flip_left_out/*popExit*/)
// 替換Fragment
.replace(R.id.container, new CardBackFragment())
// 將該事務添加到返回棧,這樣才能響應返回按鈕操作
.addToBackStack(null)
// 提交事務
.commit();
// 延遲更新菜單
mHandler.post(new Runnable() {
@Override
public void run() {
invalidateOptionsMenu();
}
});
}
car_flip_right_in.xml
card_flip_right_out.xml
card_flip_left_in.xml 和car_flip_right_in.xml差不多,只是rotationY動畫的起止角度 valueFrom=”-180”,valueTo=”0”.
card_flip_left_out.xml 和car_flip_right_out.xml差不多,只是rotationY動畫的起止角度 valueFrom=”0”,valueTo=”180”.
下面展示有何在ViewPager切換Page的時候應用動畫
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_slide);
//實例化ViewPager和PagerAdapter對象
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
invalidateOptionsMenu();
}
});
}
菜單操作
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
//...
case R.id.action_zoom:
//設置縮放動畫,在切換page的時候會看到效果
mPager.setPageTransformer(false,new ZoomPageTransformer());
return true;
case R.id.action_depth:
mPager.setPageTransformer(false,new DepthPageTransformer());
return true;
case R.id.action_default:
//恢復默認動畫
mPager.setPageTransformer(false,null);
return true;
}
return super.onOptionsItemSelected(item);
}
DepthPageTransformer.java
public class DepthPageTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(View page, float position) {
int pageWidth = page.getWidth();
if(position <= -1){
//當不在屏幕顯示范圍時,恢復所有屬性
page.setAlpha(1);
page.setTranslationX(0);
page.setScaleX(1);
page.setScaleY(1);
}else if(position < 0){
//屏幕左側page
page.setTranslationX(-position*pageWidth);
page.setScaleX(position*0.3f+1f);
page.setScaleY(position*0.3f+1f);
page.setAlpha(1+position*0.8f);
}else if(position < 1) {
//屏幕右側page
page.setTranslationX(0);
page.setScaleX(1);
page.setScaleY(1);
page.setAlpha(1);
}else{
//當不在屏幕顯示范圍時,恢復所有屬性
page.setAlpha(1);
page.setTranslationX(0);
page.setScaleX(1);
page.setScaleY(1);
}
}
}
ZoomPageTransformer.java
public class ZoomPageTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(View page, float position) {
if(position <= -1){
//當不在屏幕顯示范圍時,恢復所有屬性
page.setScaleX(1);
page.setScaleY(1);
page.setTranslationX(0);
page.setAlpha(1);
}else if(position < 1){
//在屏幕上顯示的page
float pageWidth = page.getWidth();
float pageHeight = page.getHeight();
float scaleFactor = Math.max(0.85f,1 -Math.abs(position));
page.setScaleX(scaleFactor);
page.setScaleY(scaleFactor);
page.setAlpha(scaleFactor);
float verticalMargin = pageHeight*(1-scaleFactor)/2;
float horizonMargin = pageWidth*(1-scaleFactor)/2;
if(position < 0){
page.setTranslationX(horizonMargin-verticalMargin/2);
}else {
page.setTranslationX(-horizonMargin+verticalMargin/2);
}
}else{
//當不在屏幕顯示范圍時,恢復所有屬性
page.setScaleX(1);
page.setScaleY(1);
page.setTranslationX(0);
page.setAlpha(1);
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_zoom);
mImageRcv = (RecyclerView)findViewById(R.id.rcv_images);
mAdapter = new ImageAdapter(this);
mAdapter.setOnItemClickListener(new ImageAdapter.OnItemClickListener() {
@Override
public void onItemClicked(View view, int pos) {
zoomImageFromThumb(view,mAdapter.getItemData(pos));
}
});
mImageRcv.setAdapter(mAdapter);
mImageRcv.setLayoutManager(new GridLayoutManager(this,3,
LinearLayoutManager.VERTICAL,false));
mShortAnimationDuration = getResources()
.getInteger(android.R.integer.config_shortAnimTime);
}
/**
* 動畫執行關鍵代碼
**/
private void zoomImageFromThumb(final View thumbView, int imageResId) {
// 取消上一個動畫
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
// 加載高清圖片
final ImageView expandedImageView = (ImageView) findViewById(R.id.expanded_image);
expandedImageView.setImageResource(imageResId);
// 計算尺寸,以便精准動畫
final Rect startBounds = new Rect();
final Rect finalBounds = new Rect();
final Point globalOffset = new Point();
// 獲取屏幕絕對坐標
thumbView.getGlobalVisibleRect(startBounds);
findViewById(R.id.container).getGlobalVisibleRect(finalBounds, globalOffset);
startBounds.offset(-globalOffset.x, -globalOffset.y);
finalBounds.offset(-globalOffset.x, -globalOffset.y);
//
float startScale;
if ((float) finalBounds.width() / finalBounds.height()
> (float) startBounds.width() / startBounds.height()) {
startScale = (float) startBounds.height() / finalBounds.height();
} else {
startScale = (float) startBounds.width() / finalBounds.width();
}
//隱藏縮略圖並開始動畫顯示高清圖
thumbView.setAlpha(0f);
expandedImageView.setVisibility(View.VISIBLE);
// 設置動畫的中心為坐標原點
expandedImageView.setPivotX(0f);
expandedImageView.setPivotY(0f);
// 構造動畫
AnimatorSet set = new AnimatorSet();
set
.play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left,
finalBounds.left))
.with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top,
finalBounds.top))
.with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X, startScale, 1f))
.with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_Y, startScale, 1f));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mCurrentAnimator = null;
}
@Override
public void onAnimationCancel(Animator animation) {
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
//再次點擊還原,逆過程
final float startScaleFinal = startScale;
expandedImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
AnimatorSet set = new AnimatorSet();
set
.play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left))
.with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top))
.with(ObjectAnimator
.ofFloat(expandedImageView, View.SCALE_X, startScaleFinal))
.with(ObjectAnimator
.ofFloat(expandedImageView, View.SCALE_Y, startScaleFinal));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
@Override
public void onAnimationCancel(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
}
});
}
以上就是動畫相關的知識。
Android中的事件Touch事件,四種狀態: ACTION_DOWN ——> 表示按下了屏幕,一個事件必然從ACTION_DOWN開始
需求我們知道,Android系統本身有自帶的日歷控件,網絡上也有很多開源的日歷控件資源,但是這些日歷控件往往樣式較單一,API較多,不易於在實際項目中擴展並實現出符合具體
Adapter常用的實現方式ArrayAdapter、simpleAdapter、SimpleCursorAdapter、BaseAdapter。 1、ArrayAdap
鍵盤監控 鍵盤監控,顧名思義是在應用軟件在運行時,用戶在設備上的一舉一動都將被詳細記錄下來,更多的實在使用者毫無覺察的情況下將屏幕內容以圖片的形式、按鍵內容以文本文檔的形