編輯:關於Android編程
12.1 Android5.X UI設計初步
12.1.1 材料的形態模擬 12.1.2 更加真實的動畫 12.1.3 大色塊的使用 12.2 Material Design主題 12.3 Palette 12.4 視圖與陰影 12.5 Tinting和Clipping
12.5.1 Tinting(著色) 12.5.2 Clipping(裁剪) 12.6 列表與卡片
12.6.1 RecyclerView 12.6.2 CardView 12.7 Android過渡動畫 12.8 Material Design動畫效果
12.8.1 Ripple效果 12.8.2 Circular Reveal 12.8.3 View state changes Animation 12.9 Toolbar 12.10 Notification
12.10.1 基本的Notification 12.10.2 折疊式Notification 12.10.3 懸掛式Notification 12.10.4 顯示等級的Notification
轉眼間,安卓7.0已經出了,而我還在學習5.0的知識,此刻的心情是藍瘦、香菇,看來得加把勁了,這篇文章較長,不過有很多實例的動畫確實很好看,今年是個UI火熱的一年,掌握了這些動畫,可謂是你的看家本領,也是你進階的一部分
Android5.X系列開始使用新的設計風格Material Design
Google通過模擬自然界的形態變化、關線與陰影、紙與紙之間的空間層級關系,帶來一種真實的空間感
Material Design中采用大量高飽和、適中亮度的大色塊來突出界面的主次
希望了解更多的Material Design設計風格的讀者可以訪問網站:https://www.google.com/design/
Material Design提供默認的三種主題
@android:style/Theme.Material (dark version) @android:style/Theme.Material.Light (light version) @android:style/Theme.Material.Light.DarkActionBar
同時也提出了Color Palette的概念,讓開發者自己設定系統區域的顏色
可以通過使用自定義Style來創建自己的Color Palette顏色主題
Android5.X使用Palette來提取顏色,從而讓主題能夠動態適應當前頁面的色調
Android內置了幾種提取顏色的種類:
Vibrant(充滿活力的) Vibrant dark(充滿活力的黑) Vibrant light(充滿活力的白) Muted(柔和的) Muted dark(柔和的黑) Muted light(柔和的白)使用Palette需要在Dependencies中添加依賴:
compile 'com.android.support:palette-v7:21.0.2'
這這可以給Palette傳進一個Bitmap對象,並調用它的Palette.generate()靜態方法或者Palette.generateAsync()方法創建一個Palette
下面例子演示如何通過加載圖片的柔和色調來改變狀態欄和Actionbar的色調:
public class PaletteActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.palette); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test); // 創建Palette對象 Palette.generateAsync(bitmap, new Palette.PaletteAsyncListener() { @Override public void onGenerated(Palette palette) { // 通過Palette來獲取對應的色調 Palette.Swatch vibrant = palette.getDarkVibrantSwatch(); // 將顏色設置給相應的組件 getSupportActionBar().setBackgroundDrawable( new ColorDrawable(vibrant.getRgb())); Window window = getWindow(); window.setStatusBarColor(vibrant.getRgb()); } }); } }
使用書上源碼會出現空指針錯誤,我們稍微把程序修改一下,查看效果圖:
Material Design最重要的特點就是擬物扁平化
Android5.X在以外的View中只有x和y的方向上添加了z方向,View的z值由兩部分組成:
Z = elevation + translationZ;
通常可以在XML布局文件中設置View的視圖高度
android:elevation="XXdp"
下面通過實例演示不同視圖高度的效果:
在程序中也可以用代碼變換視圖高度:
view.setTranslationZ(xxx);
通常和還可以用屬性動畫來改變視圖高度:
if(flag){ view.animate().translationZ(100); flag = false; }else { view.animate().translationZ(0); flag = true; }
Android5.X提供了兩個對操作圖像的新功能:Tinting和Clipping
下面有例子說明,注意tint和tintMode屬性:
效果圖:
使用Clipping,首先需要使用ViewOutlineProvider來修改outline,然後再通過setOutlinProvider將outline作用給視圖
下面通過例子理解Clipping:
在代碼中:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); View v1 = findViewById(R.id.tv_rect); View v2 = findViewById(R.id.tv_circle); //獲取Outline ViewOutlineProvider viewOutlineProvider1 = new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { //修改outline為特定形狀 outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), 30); } }; //獲取Outline ViewOutlineProvider viewOutlineProvider2 = new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { //修改outline為特定形狀 outline.setOval(0, 0, view.getWidth(), view.getHeight()); } }; //重新設置形狀 v1.setOutlineProvider(viewOutlineProvider1); v2.setOutlineProvider(viewOutlineProvider2); } }
效果圖:
關於這章,可以在我博客上已經寫過了,那麼就不再多寫了
傳送門:
Android基礎控件——RecyclerView實現拖拽排序側滑刪除效果 Android基礎控件——CardView的使用、仿支付寶銀行卡
在Activity之間的跳轉中,通過overridePendingtransition(int inId,int outId)這個方法給Activity添加一些切換動畫,效果也是差強人意
Android5.X提供了三種Transition類型的動畫:
進入:一個進入的過渡動畫決定Activity中的所有視圖怎麼進入屏幕 退出:一個退出的過渡動畫決定Activity中的所有視圖怎麼退出屏幕 共享元素:一個共享元素過渡動畫決定兩個Activity之間的過渡,怎麼共享他們的視圖其中,進人和退出效果包括:
explode(分解)一一從屏幕中間進或出,移動視圖 slide(滑動)——從屏幕邊緣進或出,移動視圖 fade(淡出) 一一通過改變屏幕上視圖的不透明度達到添加或者移除視圖共享元素包括(簡單的說ActivityA的指定的View不會消失,帶著View跳轉到ActivityB中):
changeBounds——改變目標視圖的布局邊界 changeClipBounds——裁剪目標視圖邊界 changeTransfrom——改變目標視圖的縮放比例和旋轉角度 changeImageTransfrom——改變目標圖片的大小和縮放比例這裡比如ActivityA跳轉到ActivityB,運用這三種過渡動畫,則在ActivityA中修改:
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
而在ActivityB,只需要設置以下代碼:
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
或者在ActivityB的樣式文件設置如下代碼:
- true
那麼接下來可以設置進入ActivityB的動畫效果:
getWindow().setEnterTransition(new Explode()); getWindow().setEnterTransition(new Slide()); getWindow().setEnterTransition(new Fade());
或者是設置離開ActivityB的動畫效果:
getWindow().setExitTransition(new Explode()); getWindow().setExitTransition(new Slide()); getWindow().setExitTransition(new Fade());
下面是共享元素的使用,首先在ActivityA中設置共享元素的屬性:
android:transitionName="XXX"
同時在ActivityB中設置相同的共享元素的屬性:
android:transitionName="XXX"
在代碼中使用共享元素,首先是單個共享元素:
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this,view,"share").toBundle());
或者一個視圖中有多個共享元素,通過Pair.create()來創建多個共享元素:
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this, Pair.create(view,"share"),Pair.create(fab,"fab")).toBundle());
Android5.X切換動畫例子……見經典代碼回顧案例一
無知識點
Ripple效果:點擊後的波紋效果,可以通過代碼設置波紋背景
//波紋有邊界 android:background="?android:attr/selectableItemBackground" //波紋無邊界 android:background="?android:attr/selectableItemBackgroundBorderless"
下面通過例子來演示一下這兩個效果:
效果圖:
同樣的,也可以通過XML來聲明一個ripple,然後在布局文件中使用:
效果圖:
這個動畫效果具體變現為一個View以圓形的形式展開,揭示出來,通過ViewAnimationUtils.createCircularReveal()來創建動畫,代碼如下:
public static Animator createCircularReveal(View view, int centerX, int centerY, float startRadius, float endRadius) { return new RevealAnimator(view,centerX,centerY,startRadius,endRadius); }
RevealAnimator的使用特別簡單,主要就是幾個關鍵的坐標點:
centerX 動畫開始的中心點X centerY 動畫開始的中心點Y startRadius 動畫開始半徑 endRadius 動畫結束半徑接下來我們來看一下例子,了解下RevealAnimator的使用,首先用XML創建一個圓和方形:
然後在布局文件中使用這兩個圖形:
主程序:
public class CircularReveal extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_circular_reveal); final View oval = findViewById(R.id.oval); oval.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Animator animator = ViewAnimationUtils.createCircularReveal(oval, oval.getWidth() / 2, oval.getHeight() / 2, oval.getWidth(), 0); animator.setInterpolator(new AccelerateDecelerateInterpolator()); animator.setDuration(2000); animator.start(); } }); final View rect = findViewById(R.id.rect); rect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Animator animator = ViewAnimationUtils.createCircularReveal(rect, 0, 0, 0, (float) Math.hypot(rect.getWidth(), rect.getHeight())); animator.setInterpolator(new AccelerateInterpolator()); animator.setDuration(2000); animator.start(); } }); } }
效果圖:
StateListAnimator:視圖動畫效果,以前的Selector用來修改背景達到反饋效果,現在支持Selector使用動畫效果在XML定義一個StateListAnimator,添加到Selector中:
在布局文件中直接使用:
特別要注意:Animator是要開啟的,所以必須在主代碼中使用AnimatorInflater.loadStateListAnimator()方法,並且通過View.setStateListAnimator()方法分配到視圖中
animated-selector:同樣作為一種狀態改變的動畫效果Selector首先得有一套狀態變換圖:
然後在XML中定義這些圖片組合:
最後在主程序中使用即可:
public class AnimatedSelectorActivity extends AppCompatActivity { private boolean mIsCheck; private static final int[] STATE_CHECKED = new int[]{ android.R.attr.state_checked}; private static final int[] STATE_UNCHECKED = new int[]{}; private ImageView mImageView; private Drawable mDrawable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_animated_selector); mImageView = (ImageView) findViewById(R.id.image); mDrawable = getResources().getDrawable( R.drawable.fab_anim); mImageView.setImageDrawable(mDrawable); } public void anim(View view) { if (mIsCheck) { mImageView.setImageState(STATE_UNCHECKED, true); mIsCheck = false; } else { mImageView.setImageState(STATE_CHECKED, true); mIsCheck = true; } } }
效果圖:
Toolbar與ActionBar最大的區別就是Toolbar更加自由、可控,這也是Google逐漸使用Toolbar替代Actionbar的原因,使用Toolbar必須引入appcompat-v7包,並設置主題為NoActionBar,使用以下代碼進行設置:
Toolbar的使用……見經典代碼回顧案例二
Android5.0對Notification進行了優化:
長按Notification可以顯示消息來源 鎖屏狀態下,可以看到Notification的通知
基本的Notification……見經典代碼回顧案例三
折疊式Notification……見經典代碼回顧案例四
懸掛式Notification……見經典代碼回顧案例五
Notification分為三個等級:
VISIBILITY_PRIVATE:表明只有當沒有鎖屏的時候會顯示 VISIBILITY_PUBLIC:表明在任何情況下都會顯示 VISIBILITY_SECRET:表明在pin、password等安全鎖和沒有鎖屏的情況下顯示設置Notification的等級非常簡單,只需在案例三四五增加一句:
builder.setVisibility(Notification.VISIBILITY_PUBLIC);
同時,Notificatio還提供了其他方法:
設置Notification背景顏色
builder.setColor(Color.RED);
設置Notification的category接口,用來確定Notification的顯示位置
builder.setCategory(Notification.CATEGORY_MESSAGE);
分別看下ActivityA和ActivityB的布局文件,注意transitionName在哪個View:
分別看下ActivityA和ActivityB的Activity文件:
public class TransitionsA extends Activity { private Intent intent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_transition); } // 設置不同動畫效果 public void explode(View view) { intent = new Intent(this, TransitionsB.class); intent.putExtra("flag", 0); startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this) .toBundle()); } // 設置不同動畫效果 public void slide(View view) { intent = new Intent(this, TransitionsB.class); intent.putExtra("flag", 1); startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this) .toBundle()); } // 設置不同動畫效果 public void fade(View view) { intent = new Intent(this, TransitionsB.class); intent.putExtra("flag", 2); startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this) .toBundle()); } // 設置不同動畫效果 public void share(View view) { View fab = findViewById(R.id.fab_button); intent = new Intent(this, TransitionsB.class); intent.putExtra("flag", 3); // 創建單個共享元素 // startActivity(intent, // ActivityOptions.makeSceneTransitionAnimation( // this, view, "share").toBundle()); startActivity(intent, ActivityOptions.makeSceneTransitionAnimation( this, // 創建多個共享元素 Pair.create(view, "share"), Pair.create(fab, "fab")).toBundle()); } }
public class TransitionsB extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); int flag = getIntent().getExtras().getInt("flag"); // 設置不同的動畫效果 switch (flag) { case 0: getWindow().setEnterTransition(new Explode()); break; case 1: getWindow().setEnterTransition(new Slide()); break; case 2: getWindow().setEnterTransition(new Fade()); getWindow().setExitTransition(new Fade()); break; case 3: break; } setContentView(R.layout.activity_transition_to); } }
記得先將主題設置為NoActionBar主題,在布局中聲明ToolBar
在Menu文件夾中創建一個Menu的XML文件
在代碼中使用
public class ToolbarActivity extends AppCompatActivity { private ShareActionProvider mShareActionProvider; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_toolbar); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar.setLogo(R.mipmap.ic_launcher); toolbar.setTitle("主標題"); toolbar.setSubtitle("副標題"); setSupportActionBar(toolbar); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return super.onCreateOptionsMenu(menu); } }
修改一下布局,實現Toolbar側滑菜單
在主代碼中實現:
public class ToolbarActivity extends AppCompatActivity { private ShareActionProvider mShareActionProvider; private DrawerLayout mDrawerLayout; private ActionBarDrawerToggle mDrawerToggle; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_toolbar); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar.setLogo(R.mipmap.ic_launcher); toolbar.setTitle("主標題"); toolbar.setSubtitle("副標題"); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer); mDrawerToggle = new ActionBarDrawerToggle( this, mDrawerLayout, toolbar, R.string.abc_action_bar_home_description, R.string.abc_action_bar_home_description_format); mDrawerToggle.syncState(); mDrawerLayout.setDrawerListener(mDrawerToggle); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); /* ShareActionProvider配置 */ mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(menu .findItem(R.id.action_share)); Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/*"); mShareActionProvider.setShareIntent(intent); return super.onCreateOptionsMenu(menu); } }
public class Notification01 extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_notification01); //第一步:初始化 Notification.Builder builder = new Notification.Builder(this); //第二步:構建點擊之後的意圖 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.baidu.com")); //構造pendingdintent PendingIntent pendingIntent = PendingIntent.getActivities(this, 0, new Intent[]{intent}, 0); //第三步:設置通知欄的各種消息 builder.setSmallIcon(R.mipmap.ic_launcher); builder.setContentIntent(pendingIntent); builder.setAutoCancel(true); builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)); builder.setContentText("Title"); builder.setContentText("內容"); builder.setSubText("text"); //第四步:通過NotificationManager來發出 NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); notificationManager.notify(0, builder.build()); } }
public class Notification02 extends AppCompatActivity { private static final int NOTIFICATION_ID_COLLAPSE = 0x01; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_notification02); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.sina.com")); PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, intent, 0); Notification.Builder builder = new Notification.Builder(this); builder.setSmallIcon(R.mipmap.ic_launcher); builder.setContentIntent(pendingIntent); builder.setAutoCancel(true); builder.setLargeIcon(BitmapFactory.decodeResource( getResources(), R.mipmap.ic_launcher)); // 通過RemoteViews來創建自定義的Notification視圖 RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.notification); contentView.setTextViewText(R.id.textView, "show me when collapsed"); Notification notification = builder.build(); notification.contentView = contentView; // 通過RemoteViews來創建自定義的Notification視圖 RemoteViews expandedView = new RemoteViews(getPackageName(), R.layout.notification_expanded); notification.bigContentView = expandedView; NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); nm.notify(NOTIFICATION_ID_COLLAPSE, notification); } }
public class Notification03 extends AppCompatActivity { private static final int NOTIFICATION_ID_HEADSUP = 0x01; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_notification03); Notification.Builder builder = new Notification.Builder(this) .setSmallIcon(R.mipmap.ic_launcher) .setPriority(Notification.PRIORITY_DEFAULT) .setCategory(Notification.CATEGORY_MESSAGE) .setContentTitle("Headsup Notification") .setContentText("I am a Headsup notification."); Intent push = new Intent(); push.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); push.setClass(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, push, PendingIntent.FLAG_CANCEL_CURRENT); builder.setContentText("Heads-Up Notification on Android 5.0") .setFullScreenIntent(pendingIntent, true); NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); nm.notify(NOTIFICATION_ID_HEADSUP, builder.build()); } }
經典回顧源碼下載
github:https://github.com/CSDNHensen/QunYingZhuang
ProGuard能夠對Java類中的代碼進行壓縮(Shrink),優化(Optimize),混淆(Obfuscate),預檢(Preveirfy)。 1. 壓縮(Sh
界面布局代碼
說在前面的話:這篇文章是看了如何優雅地使用NDK後,對原博客功能的補充。為了方便大家的閱讀順序,直接添加到原博客之中,如有侵犯版權,請聯系我。這篇博客有轉載,有原創,只是
最近用淘寶客戶端的時候,編輯地址的時候有個地區選擇的功能。看上面的效果覺得挺酷,滾動的時候,是最後一個從下面飛上來挨著前一個。就自己鼓搗一個出來玩玩。說了效果可能不太直觀