1.自定义Styles 统一组件风格
# styles.xml
<resources>
<style name="FormRadioButton" parent="android:Widget.CompoundButton.RadioButton">
<item name="android:minHeight">@dimen/buttonHeight</item>
<item name="android:button">@null</item>
<item name="android:background">@drawable/background_radio</item>
<item name="android:gravity">center</item>
</style>
</resources>
# activity_layout.xml
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
style="@style/FormRadioButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="One"/>
<RadioButton
style="@style/FormRadioButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Two"/>
<RadioButton
style="@style/FormRadioButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Three"/>
</RadioGroup>
2.自定义View
public class BullsEyeView extends View {
private Paint mPaint;
private Point mCenter;
private float mRadius;
/*
* Java Constructor
*/
public BullsEyeView(Context context) {
this(context, null);
}
/*
* XML Constructor
*/
public BullsEyeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/*
* XML Constructor with Style
*/
public BullsEyeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//在这里可以做自定义View的一些初始化配置
//例如,创建一个可绘画的刷子
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//设置刷子的风格
mPaint.setStyle(Style.FILL);
//创建绘画的中心点
mCenter = new Point();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width, height;
//设置大小
int contentWidth = 200;
int contentHeight = 200;
width = getMeasurement(widthMeasureSpec, contentWidth);
height = getMeasurement(heightMeasureSpec, contentHeight);
//必须调用此方法
setMeasuredDimension(width, height);
}
/*
* 辅助设置大小的方法
*/
private int getMeasurement(int measureSpec, int contentSize) {
int specSize = MeasureSpec.getSize(measureSpec);
switch (MeasureSpec.getMode(measureSpec)) {
case MeasureSpec.AT_MOST:
return Math.min(specSize, contentSize);
case MeasureSpec.UNSPECIFIED:
return contentSize;
case MeasureSpec.EXACTLY:
return specSize;
default:
return 0;
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (w != oldw || h != oldh) {
//如果大小有变,要重置中心点以及半径
mCenter.x = w / 2;
mCenter.y = h / 2;
mRadius = Math.min(mCenter.x, mCenter.y);
}
}
@Override
protected void onDraw(Canvas canvas) {
//绘制圆形
// 用不同颜色从最小到最大绘制
mPaint.setColor(Color.RED);
canvas.drawCircle(mCenter.x, mCenter.y, mRadius, mPaint);
mPaint.setColor(Color.WHITE);
canvas.drawCircle(mCenter.x, mCenter.y, mRadius * 0.8f, mPaint);
mPaint.setColor(Color.BLUE);
canvas.drawCircle(mCenter.x, mCenter.y, mRadius * 0.6f, mPaint);
mPaint.setColor(Color.WHITE);
canvas.drawCircle(mCenter.x, mCenter.y, mRadius * 0.4f, mPaint);
mPaint.setColor(Color.RED);
canvas.drawCircle(mCenter.x, mCenter.y, mRadius * 0.2f, mPaint);
}
}
3.View动画
View.animate()
ObjectAnimator
AnimatorSet
4.Layout动画
removeView(View)
addView(View, LayoutParams)
layout.xml需要添加:android:animateLayoutChanges="true"
Layout.setLayoutTransition(LayoutTransition)
5.自定义ListView
# res/drawable/row_background_default.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#EFEFEF"
android:endColor="#989898"
android:type="linear"
android:angle="270" />
</shape>
# res/drawable/row_background_pressed.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#0B8CF2"
android:endColor="#0661E5"
android:type="linear"
android:angle="270" />
</shape>
# res/drawable/row_background.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/row_background_pressed"/>
<item android:drawable="@drawable/row_background_default"/>
</selector>
# res/layout/custom_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dip"
android:background="@drawable/row_background">
<TextView
android:id="@+id/line1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
6.简洁易懂的自定义组件
public class TextImageButton extends FrameLayout {
private ImageView imageView;
private TextView textView;
public TextImageButton(Context context) {
this(context, null);
}
public TextImageButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TextImageButton(Context context, AttributeSet attrs,
int defaultStyle) {
// 用默认button风格初始化layout
// 当前主题设置了可点击属性以及背景
super(context, attrs, android.R.attr.buttonStyle);
//创建子类视图
imageView = new ImageView(context, attrs, defaultStyle);
textView = new TextView(context, attrs, defaultStyle);
//为子类视图创建LayoutParams
FrameLayout.LayoutParams params = new
FrameLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT,
Gravity.CENTER);
//添加子类视图
this.addView(imageView, params);
this.addView(textView, params);
//如果有图片,显示图片
if(imageView.getDrawable() != null) {
textView.setVisibility(View.GONE);
imageView.setVisibility(View.VISIBLE);
} else {
textView.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
}
}
/* 属性设置 */
public void setText(CharSequence text) {
//切换至Text视图
textView.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
//设置Text值
textView.setText(text);
}
public void setImageResource(int resId) {
//切换至图片视图
textView.setVisibility(View.GONE);
imageView.setVisibility(View.VISIBLE);
//设置图片资源
imageView.setImageResource(resId);
}
public void setImageDrawable(Drawable drawable) {
//切换至图片视图
textView.setVisibility(View.GONE);
imageView.setVisibility(View.VISIBLE);
//设置图片Drawable
imageView.setImageDrawable(drawable);
}
}
7.自定义过渡动画
# startActivity()后的动画
res/anim/activity_open_enter.xml
res/anim/activity_open_exit.xml
# finish()后的动画
res/anim/activity_close_enter.xml
res/anim/activity_close_exit.xml
# res/anim/xxxx.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:fromDegrees="90" android:toDegrees="0"
android:pivotX="0%" android:pivotY="0%"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
android:duration="500" />
<alpha
android:fromAlpha="0.0" android:toAlpha="1.0"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
android:duration="500" />
</set>
//开启新的acitvity的动画效果
Intent intent = new Intent(...);
startActivity(intent);
overridePendingTransition(R.anim.activity_open_enter, R.anim.activity_open_exit);
//关闭当前activity的动画效果
finish();
overridePendingTransition(R.anim.activity_close_enter, R.anim.activity_close_exit);
# res/values/styles.xml
<resources>
<style name="AppTheme" parent="android:Theme.Holo.Light">
<item name="android:windowAnimationStyle">
@style/ActivityAnimation</item>
</style>
<style name="ActivityAnimation"
parent="@android:style/Animation.Activity">
<item name="android:activityOpenEnterAnimation">
@anim/activity_open_enter</item>
<item name="android:activityOpenExitAnimation">
@anim/activity_open_exit</item>
<item name="android:activityCloseEnterAnimation">
@anim/activity_close_enter</item>
<item name="android:activityCloseExitAnimation">
@anim/activity_close_exit</item>
</style>
</resources>
- 支持库中的Fragments的用法
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
//必须第一个调用
ft.setCustomAnimations(R.anim.activity_open_enter,
R.anim.activity_open_exit,
R.anim.activity_close_enter,
R.anim.activity_close_exit);
ft.replace(R.id.container_fragment, fragment);
ft.addToBackStack(null);
ft.commit();
或者
// 覆写onCreateAnimation()方法
@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
switch (transit) {
case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
if (enter) {
return AnimationUtils.loadAnimation(getActivity(),
android.R.anim.fade_in);
} else {
return AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out);
}
case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
if (enter) {
return AnimationUtils.loadAnimation(getActivity(), R.anim.activity_close_enter);
} else {
return AnimationUtils.loadAnimation(getActivity(), R.anim.activity_close_exit);
}
case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
default:
if (enter) {
return AnimationUtils.loadAnimation(getActivity(), R.anim.activity_open_enter);
} else {
return AnimationUtils.loadAnimation(getActivity(), R.anim.activity_open_exit);
}
}
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
//设置动画效果
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.replace(R.id.container_fragment, fragment);
ft.addToBackStack(null);
ft.commit();
8.创建View的变化
@Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
// 清除已有的变化
t.clear();
if (getOrientation() == HORIZONTAL) {
// 基于离左边缘距离来改变子类View
float delta = 1.0f - ((float) child.getLeft() / getWidth());
t.getMatrix().setScale(delta, delta, child.getWidth() / 2, child.getHeight() / 2);
} else {
//基于离上边缘距离来改变子类View
float delta = 1.0f - ((float) child.getTop() / getHeight());
t.getMatrix().setScale(delta, delta, child.getWidth() / 2, child.getHeight() / 2);
//基于子类View的位置渐变
t.setAlpha(delta);
}
return true;
}