1. Button
https://material.io/develop/android/components/buttons
原來Button設置不同的style就可以有不同的效果啊,以前一直都自定義的。
1.1 Text button
<Button
android:id="@+id/textButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text button"
style="@style/Widget.MaterialComponents.Button.TextButton"
/>
還可以加Icon,之前以爲只有MaterialButton裏才支持這個
<Button
<Button
app:icon="@drawable/ic_volume"
app:iconSize="30dp"
app:iconTint="@color/colorAccent"
app:iconGravity="textStart"
app:iconPadding="5dp"
style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
2.2 Outlined button
are medium-emphasis buttons. They contain actions that are important, but aren’t the primary action in an app.
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
//or
style="?attr/materialButtonOutlinedStyle"
3.3 Contained button
默認的就這種,背景是colorPrimary顏色
3.4 Toggle button
帶狀態切換的,需要一個容器
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/toggleButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 1"
style="?attr/materialButtonOutlinedStyle"
/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 2"
style="?attr/materialButtonOutlinedStyle"
/>
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 3"
style="?attr/materialButtonOutlinedStyle"
/>
</com.google.android.material.button.MaterialButtonToggleGroup>
圓角選項卡的實現方法
1.1 使用button
<com.google.android.material.button.MaterialButtonToggleGroup
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="20dp"
app:checkedButton="@id/btn_1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
app:selectionRequired="true"
app:singleSelection="true">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_1"
style="@style/TabSingleCheckedForSettings"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="car"
app:icon="@drawable/ic_vpi_car_d"
app:shapeAppearanceOverlay="@style/TabLeftShapeRoundCornerTop" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_2"
style="@style/TabSingleCheckedForSettings"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="suv"
app:icon="@drawable/ic_vpi_suv_d" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_3"
style="@style/TabSingleCheckedForSettings"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="towing"
app:icon="@drawable/ic_vpi_towing_d" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_4"
style="@style/TabSingleCheckedForSettings"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="truck"
app:icon="@drawable/ic_vpi_truck_d"
app:shapeAppearanceOverlay="@style/TabRightShapeRoundCornerTop" />
</com.google.android.material.button.MaterialButtonToggleGroup>
用到的style
<style name="TabSingleCheckedForSettings">
<item name="strokeColor">@color/colorPrimary2</item>
<item name="strokeWidth">@dimen/mtrl_btn_stroke_size</item>
<item name="backgroundTint">@color/select_trans_primary</item>
<item name="android:textColor">@color/select_tab_text_color</item>
<item name="iconTint">@color/select_tab_text_color</item>
<item name="iconSize">25dp</item>
<item name="iconGravity">textStart</item>
<item name="iconPadding">5dp</item>
<item name="android:textSize">26sp</item>
<item name="android:insetTop">0dp</item>
<item name="android:insetBottom">0dp</item>
<item name="android:stateListAnimator">@null</item>
</style>
<style name="TabLeftShapeRoundCornerTop">
<item name="cornerSizeTopLeft">50%</item>
<item name="cornerSizeBottomLeft">50%</item>
</style>
<style name="TabRightShapeRoundCornerTop">
<item name="cornerSizeTopRight">50%</item>
<item name="cornerSizeBottomRight">50%</item>
</style>
用到的colors
select_trans_primary.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/colorPrimary2" android:state_checked="true" />
<item android:color="@color/transparent" android:state_checked="false"/>
</selector>
文本,icon顏色 select_tab_text_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/content_black_color" android:state_checked="true"/>
<item android:color="@color/colorPrimary2" android:state_checked="false"/>
</selector>
1.2 使用TabLayout ,外邊套個CardView來處理圓角,分割線用divider
不過了TabLayout 只有文字上的icon,沒有左邊的,我們可能要拿到textview設置drawableLeft了?
或者用自定義view來設置tab
MaterialContainerTransform
A shared element {@link Transition} that transforms one container to another.
MaterialContainerTransform can be used to morph between two Activities, Fragments, Views or a View to a Fragment.
public final class MaterialContainerTransform extends Transition {
//指出是入場還是出廠動畫
@IntDef({TRANSITION_DIRECTION_AUTO, TRANSITION_DIRECTION_ENTER, TRANSITION_DIRECTION_RETURN})
@Retention(RetentionPolicy.SOURCE)
public @interface TransitionDirection {}
//淡入淡出模式
@IntDef({FADE_MODE_IN, FADE_MODE_OUT, FADE_MODE_CROSS, FADE_MODE_THROUGH})
@Retention(RetentionPolicy.SOURCE)
public @interface FadeMode {}
//匹配寬或者高
@IntDef({FIT_MODE_AUTO, FIT_MODE_WIDTH, FIT_MODE_HEIGHT})
@Retention(RetentionPolicy.SOURCE)
public @interface FitMode {}
1.1 在兩個fragment之間進行轉場動畫
①首先在共享view加上一樣的transitionName名字,比如
<!--fragment_a.xml-->
<View
android:id="@+id/start_view"
android:transitionName="shared_element_container" />
<!--fragment_b.xml-->
<View
android:id="@+id/end_view"
android:transitionName="shared_element_container" />
②給即將跳轉的FragmentB 設置sharedElementEnterTransition ,可以在new出來的fragment b對象上設置,也可以直接在Fragment b裏設置,如下兩種都行.
// FragmentA.kt
val fragmentB = FragmentB()
fragmentB.sharedElementEnterTransition = MaterialContainerTransform()
/*** OR ***/
// FragmentB.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sharedElementEnterTransition = MaterialContainerTransform()
}
③設置共享元素
childFragmentManager
.beginTransaction()
// Map the start View in FragmentA and the transitionName of the end View in FragmentB
.addSharedElement(view, "shared_element_container")
.replace(R.id.fragment_container, fragmentB, FragmentB.TAG)
.addToBackStack(FragmentB.TAG)
.commit()
方法源碼註解
/**
* Used with custom Transitions to map a View from a removed or hidden
* Fragment to a View from a shown or added Fragment.
* <var>sharedElement</var> must have a unique transitionName in the View hierarchy.
*
* @param sharedElement A View in a disappearing Fragment to match with a View in an
* appearing Fragment.
* @param name The transitionName for a View in an appearing Fragment to match to the shared
* element.
* @see Fragment#setSharedElementReturnTransition(Object)
* @see Fragment#setSharedElementEnterTransition(Object)
*/
@NonNull
public FragmentTransaction addSharedElement(@NonNull View sharedElement, @NonNull String name)
然後測試結果還湊合,不過嘗試修改FragmentB裏sharedElementEnterTransition的duration時間,改長點,比如2秒,然後就發現,從A到B變化的時候,會先出現一個淺灰色的背景,然後動畫在這個灰色的背景上發生,看着效果不太好,後退的時候動畫沒啥問題.
1.2 activity 之間跳轉動畫
Note: Activity and Window transitions require using Android Framework Transitions provided in the com.google.android.material.transition.platform package and are only available on API level 21 and above.
transition目錄下的類ABC等,在platform下都有同名的ABC,這裏意思是用platform下的
另外對於viedeoview,surfaceView之類的,不要用這個跳轉,效果不行還可能出現異常.因爲他們都不在ui線程更新的,有自己的線程處理,會出問題.
使用步驟,假設從A跳到B
① AB 都需要 activity transition feature,可以在代碼裏設置,也可以在style裏設置.
override fun onCreate(savedInstanceState: Bundle?) {
// Enable Activity Transitions. Optionally enable Activity transitions in your
// theme with <item name=”android:windowActivityTransitions”>true</item>.
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
另外A 需要如下設置,也是在onCreate裏,跟在上邊的requestFeature下面即可
// Attach a callback used to capture the shared elements from this Activity to be used
// by the container transform transition
setExitSharedElementCallback(MaterialContainerTransformSharedElementCallback())
// Keep system bars (status bar, navigation bar) persistent throughout the transition.
window.sharedElementsUseOverlay = false
② A 跳轉代碼
sharedView.setTransitionName("xxxx")//在A裏是唯一的就行
val options = ActivityOptions.makeSceneTransitionAnimation(
this,
sharedView,//A 裏要進行動畫的view
"shared_element_container" // The transition name to be matched in Activity B.
)
startActivity(Intent(this, B.class),options.toBundle())
③ B裏的設置
下邊默認的是用的B整個佈局做爲跳轉對象的,你也可以用B裏邊的某些view或viewgroup來作爲跳轉對象,
override fun onCreate(savedInstanceState: Bundle?) {
// Enable Activity Transitions. Optionally enable Activity transitions in your
// theme with <item name=”android:windowActivityTransitions”>true</item>.
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
// Set the transition name, which matches Activity A’s start view transition name, on
// the root view.
findViewById<View>(android.R.id.content).transitionName = "shared_element_container"
// Attach a callback used to receive the shared elements from Activity A to be
// used by the container transform transition.
setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback())
// Set this Activity’s enter and return transition to a MaterialContainerTransform
window.sharedElementEnterTransition = MaterialContainerTransform().apply {
addTarget(android.R.id.content)
duration = 300L
setAllContainerColors(Color.WHITE)//activity B 可能沒有設置背景,跳轉的時候有可能看到底層,不太好看
}
window.sharedElementReturnTransition = MaterialContainerTransform().apply {
addTarget(android.R.id.content)
duration = 250L
setAllContainerColors(Color.WHITE)// startView 可能沒有背景,透明的不太好看,可以加個這個
}
super.onCreate(bundle)
setContentView(R.layout.activity_b)
...
}
1.3 view 之間的轉換
試了下,不知道啥用,關鍵是動畫前啥樣子,動畫結束後又還原了,比如demo裏,startView從可見到不可見,endView相反,可動畫結束又成老樣子了.
我把代碼複製到別的demo是正常的,後來發現這裏出問題是因爲容器是MotionLayout,不知道這個爲啥會影響這個,可能motionlayout自己就能管理動畫吧
val transform = MaterialContainerTransform().apply {
// Manually tell the container transform which Views to transform between.
startView = fab
endView = bottomToolbar
// Ensure the container transform only runs on a single target
addTarget(endView)
// Optionally add a curved path to the transform
pathMotion = MaterialArcMotion()
// Since View to View transforms often are not transforming into full screens,
// remove the transition's scrim.
scrimColor = Color.TRANSPARENT
}
// Begin the transition by changing properties on the start and end views or
// removing/adding them from the hierarchy.
TransitionManager.beginDelayedTransition(container, transform)
fab.visibility = View.GONE
bottomToolbar.visibility = View.VISIBLE
Motion
- transition
相關的一些類學習,至於啥用再說
1.1 VisibilityAnimatorProvider
接口名字基本就說明了它是幹啥的了,爲可見性提供動畫的,出現和消失的animator
public interface VisibilityAnimatorProvider {
/**
* Should return an Animator that animates in the appearing target {@code view}.
*
* @param sceneRoot The root of the transition hierarchy, which can be useful for checking
* configurations such as RTL
* @param view The view that is appearing
*/
@Nullable
Animator createAppear(@NonNull ViewGroup sceneRoot, @NonNull View view);
/**
* Should return an Animator that animates out the disappearing target {@code view}.
*
* @param sceneRoot The root of the transition hierarchy, which can be useful for checking
* configurations such as RTL
* @param view The view that is disappearing
*/
@Nullable
Animator createDisappear(@NonNull ViewGroup sceneRoot, @NonNull View view);
}
系統有4個實現類
FadeProvider
就是透明度的變化,默認appear是從0到incomingEndThreshold【defautlvalue是1,可修改】,disappear是從1到0不可修改
/** A class that configures and is able to provide an {@link Animator} that fades a view. */
public final class FadeProvider implements VisibilityAnimatorProvider {
}
FadeThroughProvider
和上邊的差不多,不過這個有個固定的閥值,透明度是從0.35到1 ,從1到0.35
/**
* A class that configures and is able to provide an {@link Animator} that fades out or in a view.
*
* <p>FadeThroughProvider differs from FadeProvider in that it fades out and in views sequentially.
*/
public final class FadeThroughProvider implements VisibilityAnimatorProvider {
static final float PROGRESS_THRESHOLD = 0.35f;
}
ScaleProvider
就是提供拉伸動畫,出現的時候是從0.8到1 ,消失的時候是從1到1.1
public final class ScaleProvider implements VisibilityAnimatorProvider {
private float outgoingStartScale = 1f;
private float outgoingEndScale = 1.1f;
private float incomingStartScale = 0.8f;
private float incomingEndScale = 1f;
SlideDistanceProvider
這個是平移動畫,構造方法裏需要一個Gravity的參數,指明最終停留的邊界,當然是從另一邊移動過來的,
上下左右,還可以設置移動距離,如果不設置有個默認的距離30dp
/**
* A class that can configure and create an {@link Animator} that slides a view vertically or
* horizontally slide over a specific distance.
*/
public final class SlideDistanceProvider implements VisibilityAnimatorProvider {
public SlideDistanceProvider(@GravityFlag int slideEdge) {
this.slideEdge = slideEdge;
}
private static Animator createTranslationAppearAnimator(
View sceneRoot, View view, @GravityFlag int slideEdge, @Px int slideDistance) {
switch (slideEdge) {
case Gravity.LEFT:
return createTranslationXAnimator(view, slideDistance, 0);
case Gravity.TOP:
return createTranslationYAnimator(view, -slideDistance, 0);
case Gravity.RIGHT:
return createTranslationXAnimator(view, -slideDistance, 0);
case Gravity.BOTTOM:
return createTranslationYAnimator(view, slideDistance, 0);
case Gravity.START:
return createTranslationXAnimator(
view, isRtl(sceneRoot) ? slideDistance : -slideDistance, 0);
case Gravity.END:
return createTranslationXAnimator(
view, isRtl(sceneRoot) ? -slideDistance : slideDistance, 0);
default:
throw new IllegalArgumentException("Invalid slide direction: " + slideEdge);
}
}
2. Transition
A Transition holds information about animations that will be run on its targets during a scene change
public abstract class Transition implements Cloneable {
public Transition addTarget(@NonNull View target)