1. 在android中怎樣讓按鈕漂浮在圖片上
android懸浮按鈕(Floating action button)的兩種實現方法
最近android中有很多新的設計規范被引入,最流行的莫過於被稱作Promoted Actions的設計了,Promoted Actions是指一種操作按鈕,它不是放在actionbar中,而是直接在可見的UI布局中(當然這里的UI指的是setContentView所管轄的范圍)。因此它更容易在代碼中被獲取到(試想如果你要在actionbar中獲取一個菜單按鈕是不是很難?),Promoted Actions往往主要用於一個界面的主要操作,比如在email的郵件列表界面,promoted action可以用於接受一個新郵件。promoted action在外觀上其實就是一個懸浮按鈕,更常見的是漂浮在界面上的圓形按鈕,一般我直接將promoted action稱作懸浮按鈕,英文名稱Float Action Button簡稱(FAB,不是FBI哈)。
floatactionbutton是android l中的產物,但是我們也可以在更早的版本中實現。假設我這里有一個列表界面,我想使用floatactionbutton代表添加新元素的功能,界面如下:
要實現floatactionbutton可以有多種方法,一種只適合android L,另外一種適合任意版本。
用ImageButton實現
這種方式其實是在ImageButton的屬性中使用了android L才有的一些特性:
<ImageButton
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/plus"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:tint="@android:color/white"
android:id="@+id/fab"
android:elevation="1dp"
android:background="@drawable/ripple"
android:stateListAnimator="@anim/fab_anim"
/>
仔細一點,你會發現我們將這個ImageButton放到了布局的右下角,為了實現floatactionbutton應該具備的效果,需要考慮以下幾個方面:
·Background
·Shadow
·Animation
背景上我們使用ripple drawable來增強吸引力。注意上面的xml代碼中我們將background設置成了@drawable/ripple,ripple drawable的定義如下:
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?android:colorControlHighlight">
<item>
<shape android:shape="oval">
<solid android:color="?android:colorAccent" />
</shape>
</item>
</ripple>
既然是懸浮按鈕,那就需要強調維度上面的感覺,當按鈕被按下的時候,按鈕的陰影需要擴大,並且這個過程是漸變的,我們使用屬性動畫去改變translatioz。
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_enabled="true"
android:state_pressed="true">
<objectAnimator
android:ration="@android:integer/config_shortAnimTime"
android:propertyName="translationZ"
android:valueFrom="@dimen/start_z"
android:valueTo="@dimen/end_z"
android:valueType="floatType" />
</item>
<item>
<objectAnimator
android:ration="@android:integer/config_shortAnimTime"
android:propertyName="translationZ"
android:valueFrom="@dimen/end_z"
android:valueTo="@dimen/start_z"
android:valueType="floatType" />
</item>
</selector>
使用自定義控制項的方式實現懸浮按鈕
這種方式不依賴於android L,而是碼代碼。
首先定義一個這樣的類:
public class CustomFAB extends ImageButton {
...
}
然後是讀取一些自定義的屬性(假設你了解styleable的用法)
private void init(AttributeSet attrSet) {
Resources.Theme theme = ctx.getTheme();
TypedArray arr = theme.obtainStyledAttributes(attrSet, R.styleable.FAB, 0, 0);
try {
setBgColor(arr.getColor(R.styleable.FAB_bg_color, Color.BLUE));
setBgColorPressed(arr.getColor(R.styleable.FAB_bg_color_pressed, Color.GRAY));
StateListDrawable sld = new StateListDrawable();
sld.addState(new int[] {android.R.attr.state_pressed}, createButton(bgColorPressed));
sld.addState(new int[] {}, createButton(bgColor));
setBackground(sld);
}
catch(Throwable t) {}
finally {
arr.recycle();
}
}
在xml中我們需要加入如下代碼,一般是在attr.xml文件中。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FAB">
<!-- Background color -->
<attr name="bg_color" format="color|reference"/>
<attr name="bg_color_pressed" format="color|reference"/>
</declare-styleable>
</resources>
使用StateListDrawable來實現不同狀態下的背景
private Drawable createButton(int color) {
OvalShape oShape = new OvalShape();
ShapeDrawable sd = new ShapeDrawable(oShape);
setWillNotDraw(false);
sd.getPaint().setColor(color);
OvalShape oShape1 = new OvalShape();
ShapeDrawable sd1 = new ShapeDrawable(oShape);
sd1.setShaderFactory(new ShapeDrawable.ShaderFactory() {
@Override
public Shader resize(int width, int height) {
LinearGradient lg = new LinearGradient(0,0,0, height,
new int[] {
Color.WHITE,
Color.GRAY,
Color.DKGRAY,
Color.BLACK
}, null, Shader.TileMode.REPEAT);
return lg;
}
});
LayerDrawable ld = new LayerDrawable(new Drawable[] { sd1, sd });
ld.setLayerInset(0, 5, 5, 0, 0);
ld.setLayerInset(1, 0, 0, 5, 5);
return ld;
}
最後將控制項放xml中:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res/com.survivingwithandroid.fab"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MyActivity">
...
<com.survivingwithandroid.fab.CustomFAB
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@android:drawable/ic_input_add"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
custom:bg_color="@color/light_blue"
android:tint="@android:color/white"
/>
</RelativeLayout>
2. android:elevation無效
在8.0版本,添加了z軸後並沒有抬高?
android5.0 引入了Z軸的概念,於是就有著這種風格,也就是目前比較火的Material Design。
默認情況下,陰影是由background提供的,如果控制項沒有設置background,則需要加上
android:outlineProvider="bounds"
3. 01 CardView-使用
Material Design中有一種很個性的設計概念:卡片式設計(Cards),Cards擁有自己獨特的UI特徵,關於Cards的設計規范可以參考官網介紹: cards-usage Google在v7包中引進了一種全新的控制項CardView,用來實現這種 Cards UI 的設計.
CardView繼承自FrameLayout,它是一個帶 圓角 背景和 陰影 的FrameLayout. CardView官方文檔
一、簡單使用
使用前添加依賴:
compile 'com.android.support:cardview-v7:25.3.1'
1、使用
CardView本質上屬於FrameLayout,不同的是,它多了很多"特效"(圓角、陰影等).
可以看見,被CardView包裹的ImageView有明顯的圓角和陰影,這就是CardView最重要的兩條屬性了.
app:cardCornerRadius=" " 圓角的半徑,效果就是上面四個角的弧度
app:cardElevation=" " 陰影大小
2、關於Z軸的概念
Android5.0 引入了Z軸的概念,可以讓組件呈現3D效果.看下面這幅圖:
圖中的FAB( FloatingActionButton )很明顯是浮在界面上的,這就是Z軸的效果.
Z屬性 可以通過elevation和translationZ進行修改 Z= elevation+translationZ
android:elevation=" " 設置該屬性使控制項有一個陰影,感覺該控制項像是「浮」起來一樣,達到3D效果
android:translationZ="" 設置該組件陰影在Z軸(垂直屏幕方向)上的位移
在 5.0之前 ,我們如果想給View添加陰影效果,以體現其層次感,通常的做法是給View設置一個帶陰影的背景圖片.在 5.0之後 ,我們只需要簡單的修改View的 Z屬性 ,就能讓其具備陰影的層次感,不過要求版本至少5.0 Lollipop,也就是API21.
在 Android Design Support Library 和 support -v7 中一些組件已經封裝好了Z屬性,不需要5.0 就可以使用.
像 FloatingActionButton 就可以通過app:elevation=" "使用Z屬性,CardView可以通過app:cardElevation=" " 來使用.關於Z軸的更多介紹,可以觀看 官方:定義陰影與裁剪視圖 .
二、CardView的常用屬性
1、設置背景顏色
app:cardBackgroundColor=" "
2、設置padding
app:contentPadding=" "app:contentPaddingTop=" "app:contentPaddingBottom=" "app:contentPaddingLeft=" "app:contentPaddingRight=" "
Tips: 上面是CardView設置背景顏色和padding的方式,如果你直接通過android:padding=" " 和android:background=" "設置,是無效的.
3、設置Z軸的最大高度
app:cardMaxElevation=" "
4、點擊之後的漣漪效果
android:clickable="true"android:foreground="?android:attr/selectableItemBackground"Tips:如果你給CardView設置了點擊事件,就不需要設置android:clickable="true"了
如果你的CardView是可點擊的,可以通過foreground屬性使用系統定義好的RippleDrawable: selectableItemBackground ,從而達到在5.0及以上版本系統中實現點擊時的漣漪效果(Ripple),如圖:
這個漣漪效果在5.0以上版本中才能展示,在低版本上是一個普通的點擊變暗的效果.
三、兼容性問題
1、邊距問題
看下面兩幅圖:
在5.0之前的版本中設置了 app:cardElevation=" "後 CardView 會自動留出空間供陰影顯示,而5.0之後的版本中沒有預留空間. 官網也介紹了這種情況:
Before Lollipop, CardView adds padding to its content and draws shadows to that area. This padding amount is equal to maxCardElevation + (1 - cos45) * cornerRadius on the sides and maxCardElevation * 1.5 + (1 - cos45) * cornerRadius on top and bottom.
所以給CardView設置 Margin時需要兼容一下,否則在低版本上每個卡片之間的距離會特別大,浪費屏幕空間. 解決方法1: 在res/values/dimens中設置一個0dp的margin,這是為5.0之前版本使用的
<dimen name="cardview_margin">0dp</dimen>
在res/values-v21/dimens中設置一個適合的margin,為陰影預留空間,這是為5.0之後版本使用的
<dimen name="cardview_margin">12dp</dimen>
最後,給CardView設置外邊距 android:layout_margin="@dimen/cardview_margin" ,這樣就解決了低版本中邊距過大浪費屏幕空間的問題了. 解決方法2: 直接給CardView設置該屬性:
app:cardUseCompatPadding="true" 讓CardView在不同系統中使用相同的padding值,為陰影預留空間
2、圓角問題
看下面兩幅圖:
在 >=5.0(Lollipop API 21)的版本 ,CardView會直接裁剪內容元素滿足圓角的需求.在 <5.0(Lollipop API 21)的版本 ,CardView為了使內容元素不會覆蓋CardView的圓角,會添加一個 padding ,這樣一來,如果CardView設置了背景顏色,就很難看了. 解決方法: 給CardView設置該屬性:
app:cardPreventCornerOverlap="false"這條屬性的意思是:是否阻止圓角被覆蓋,默認為true設為false後,padding效果就不存在了,同時圓角也被覆蓋了該屬性對5.X設備沒什麼影響.
四、小結
總的來說,如果在高版本中使用CardView還是很舒服的,很容易實現各種效果,低版本上兼容性還不是很好.
4. 怎麼為android控制項邊緣添加陰影
為控制項設置一個有陰影感的背景圖片即可,可以使用shape
在自定義shape中增加一層或多層,並錯開,即可顯示陰影效果。為增加立體感,按鈕按下的時候,只設置一層。我們可以通過top, bottom, right 和 left 四個參數來控制陰影的方向和大小
//自定義兩種陰影效果
第一種
java"><?xmlversion="1.0"encoding="utf-8"?>
<selectorxmlns:android="http://schemas.android.com/apk/res/android">
<itemandroid:state_pressed="true">
<layer-list>
<itemandroid:left="4dp"android:top="4dp">
<shape>
<solidandroid:color="#ff58bb52"/>
<cornersandroid:radius="30dip"/>
</shape>
</item>
</layer-list>
</item>
<item>
<layer-list>
<!--第一層-->
<itemandroid:left="4dp"android:top="4dp">
<shape>
<solidandroid:color="#66000000"/>
<cornersandroid:radius="30dip"/>
<!--描邊-->
<strokeandroid:width="1dp"android:color="#ffffffff"/>
</shape>
</item>
<!--第二層-->
<itemandroid:bottom="4dp"android:right="4dp">
<shape>
<solidandroid:color="#ff58bb52"/>
<cornersandroid:radius="30dip"/>
<!--描邊-->
<strokeandroid:width="1dp"android:color="#ffffffff"/>
</shape>
</item>
</layer-list>
</item>
</selector>
第二種
<?xmlversion="1.0"encoding="utf-8"?>
<selectorxmlns:android="http://schemas.android.com/apk/res/android">
<!--點擊之後-->
<itemandroid:state_pressed="true">
<layer-list>
<itemandroid:left="4dp"android:top="4dp">
<shape>
<solidandroid:color="#ff58bb52"/>
<cornersandroid:radius="3dp"/>
</shape>
</item>
</layer-list>
</item>
<!--正常狀態-->
<item>
<layer-list>
<!--第一層-->
<itemandroid:left="2dp"android:top="2dp">
<shape>
<solidandroid:color="#66000000"/>
<cornersandroid:radius="3dp"/>
</shape>
</item>
<!--第二層-->
<itemandroid:bottom="4dp"android:right="4dp">
<shape>
<solidandroid:color="#ff58bb52"/>
<cornersandroid:radius="3dp"/>
</shape>
</item>
<!--第三層-->
<itemandroid:bottom="6dp"android:right="6dp">
<shape>
<solidandroid:color="#ffcccccc"/>
<cornersandroid:radius="3dp"/>
</shape>
</item>
</layer-list>
</item>
</selector>
設置後的效果圖如下
5. android 低版本怎麼使用 elevation 屬性
ViewPagerTransforms 是一個自定義了各種翻轉效果的開源庫,其中的各種PageTransformer使用了view的很多屬性設置方法如DepthPageTransformer中:
?
package com.ToxicBakery.viewpager.transforms;
import android.view.View;
public class DepthPageTransformer extends ABaseTransformer {
private static final float MIN_SCALE = 0.75f;
@Override
protected void onTransform(View view, float position) {
if (position <= 0f) {
view.setTranslationX(0f);
view.setScaleX(1f);
view.setScaleY(1f);
} else if (position <= 1f) {
final float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setAlpha(1 - position); ...
6. android 為什麼使用viewoutlineprovider裁剪之後的view與原來一樣
視圖的高度(elevation),通過Z屬性表現,通過他的陰影確定:z值更高的視圖投影出更大的陰影。視圖只在Z=0的平面上投影處陰影;他們不會投影陰影在其他放在下面的視圖上面和高於z=0的平面。
有更高Z值的視圖擋住Z值較低的視圖。無論如何,Z值不會影響到View的大小。
高度也是有用的,當在執行一些動作的時候創建動畫讓組件升起。
為視圖分配高度
一個View的Z值有兩個組成部分,elevation(高度)和translation(平移).elevation是一個靜態部分,translation 用於動畫:
Z = elevation + translationZ
不同高度的視圖的陰影
在布局文件中設置evelation 使用android:elevation,在代碼中使用View.setElevation()方法。
設置一個視圖的平移,使用View.setTranslationZ()方法。
新的方法ViewPropertyAnimator.z()和ViewPropertyAnimator.translationZ()可以讓你更容易的變動視圖的高度。更多的信息,看ViewPropertyAnimator的Api文檔http://developer.android.com/reference/android/view/ViewPropertyAnimator.html。和屬性動畫的開發指南:http://developer.android.com/guide/topics/graphics/prop-animation.html。
你也可以使用StateListAnimator方式定義這些文件在xml文件中。特別適用於,狀態改變時執行的動畫,比如用戶點擊按鈕。更多信息,請看動畫視圖狀態改變,下次在動畫一節講。
Z值在測量上使用和X,Y值一樣的單位。
自定義視圖陰影和輪廓
視圖的背景邊界決定了陰影的默認形狀。輪廓(Outlines)代表了圖形對象的外形狀,並確定了對觸摸反饋區的波紋。
看這個視圖,定義一個背景Drawable:
<TextView
android:id="@+id/myview"
...
android:elevation="2dp"
android:background="@drawable/myrect" />
背景是一個圓角矩形
<!-- res/drawable/myrect.xml -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#42000000" />
<corners android:radius="5dp" />
</shape>
當這個背景drawable作為視圖的輪廓,視圖投射出圓角陰影。提供一個自定義的輪廓,可以覆蓋默認視圖陰影的形狀。
在自己的代碼中自定義一個輪廓:
1.繼承ViewOutlineProvider類
2.重寫getOutline()方法
3.在視圖中設置輪廓,使用View.setOutlineProvider()方法
你可以創建橢圓和圓角矩形輪廓使用OutLine類中的方法。視圖默認的outline provider會根據視圖的背景來生成輪廓。可以設置視圖的outline provider為null,來阻止投射陰影。
裁剪視圖
裁剪視圖功能,可以讓你更容易的改變視圖的形狀。你可以裁剪視圖為了和其他的設計元素保持一致,或者改變成形狀響應用戶的輸入。你可以裁剪一個視圖的輪廓使用View.setClipToOutLine()方法,或者android:clipToOutline屬性。只有矩形,圓角矩形,圓圈的輪廓支持被裁剪,可以使用Outline.canClip()方法檢測是否支持被裁剪。
裁剪視圖到一個drawable的形狀,設置drawable作為視圖的背景(讓視圖顯示在其上),並且調用View.setClipToOutline()方法。
裁剪視圖是一個耗費的操作,裁剪視圖時不要使用形狀動畫。達到這種效果,請使用Reveal Effect 動畫
7. Android 浮窗按鈕FloatActionButton
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<其他控制項>
<android.support.design.widget.FloatingActionButton
android:id="@+id/pro_departmeng_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/pro_button"
android:onClick="onClick"
app:layout_anchor="@id/bc_pro_department"
app:layout_anchorGravity="right|top"
android:layout_marginRight="@dimen/size5"
app:rippleColor="@color/colorPrimary"
app:borderWidth="@dimen/size0"
android:elevation="@dimen/size5"
android:backgroundTint="@color/white"
app:fabSize="mini"/>
//初始化
@Bind(R.id.pro_departmeng_fab)
;
//監聽事件
proDepartmengFab.setOnClickListener(newView.OnClickListener() {
@Override
public voidonClick(View view) {
Toast.makeText(getContext(),"test",Toast.LENGTH_LONG).show();
}
});
四、屬性介紹
1、app:borderWidth=""------------------邊框寬度,通常設置為0 ,用於解決Android 5.X設備上陰影無法正常顯示的問題
2、app:backgroundTint=""---------------按鈕的背景顏色,不設置,默認使用theme中colorAccent的顏色
3、app:rippleColor=""--------------------點擊的邊緣陰影顏色
4、app:elevation=""----------------------邊緣陰影的寬度
5、app:pressedTranslationZ="16dp"-----點擊按鈕時,按鈕邊緣陰影的寬度,通常設置比elevation的數值大
8. android 低版本怎麼使用 elevation 屬性
低版本可以導入v7的兼容包,看看是否能有這個屬性:
1. android:elevation 設置該組件「浮」起來的高度,to難過過設置該屬性可以讓該組件呈現3D效果。
2. android:translationZ 設置該組件在Z方向(垂直屏幕方向)上的位移。
對應的java方法:setElevation(float) setTranslationZ(float)
9. Android 5.0 elevation 設置陰影無效
elevation 設置陰影需要注意兩點:
1、view需要設置背景
2、陰影是繪制在父控制項上的,子控制項和父控制項之間要留空隙,用padding也不行
在開發過程中有過這樣的布局:
我子Linearlayout是設置的圓角背景,結果這樣的效果是:只有圓角的便便才有一丁點的陰影,原因是父布局設置的是padding,子控制項是match_parent,空隙不足導致,將子布局改為margin,去掉父控制項的padding就行了
10. Android開發,elevation無效
在properties->android->library->islibrary把islibrary勾上