引言
相信大家在项目开发的过程中一定会有不少需要在上方显示一张图片,而在其下方显示提示标题的效果,作为一个界面的功能按钮或者单纯作为一个列表的item项,尤其是当这个item还需要显示一些动画效果时候,此时更应该当成一个整体,否则动画效果就会需要额外的调整,否则就会不协调。
一、水珠形状ItemView功能概述
所上图所示,所谓ItemView本质就是一个组合控件————上方显示一个图片作为ItenView的图标下方显示文字作为补充说明,功能和普通的ImageViewButton大同小异,优势在于扩展性更好些,客制化也更强些,可以根据不同的素材灵活组合显示各种形状的的ItenView,当然这样的需求只使用系统控件也可以实现,只不过布局就麻烦些和复杂些,而且处理还需要做额外的动画效果处理,统一为一个整体优势显然更明显。至于其中的成本就各自衡量,个人建议多复用。
二、水珠形状ItemView设计思想
无论是继承系统自有控件还是组合系统控件,核心都是重写构造方法,在构造方法里扩展自己的功能。
1、定义基本布局
实现控件布局有两种方式,一种是通过代码生成,第二种是通过xml定义。
2、提供交互反馈的效果
这里的反馈效果指的是按下的时候显示不同的图片和改变文字的颜色等,所以需要提供一个接口,而一切的交互源自Touch,前面的文章也说了通过重写onTouch可以实现自定义的交互。
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
listener.onItemDown(v);
textView.setTextColor(getResources().getColor(android.R.color.holo_blue_dark));
Log.e("TOUCHING", "onTouch: "+"fuckckck onItemDown" );
break;
case MotionEvent.ACTION_MOVE:
listener.onItemMove(v);
break;
case MotionEvent.ACTION_UP:
listener.onItemUp(v);
Log.e("TOUCHING", "onTouch: "+"fuckckck ACTION_UP" );
textView.setTextColor(getResources().getColor(android.R.color.white));
break;
case MotionEvent.ACTION_CANCEL:
Log.e("TOUCHING", "onTouch: "+"fuckckck ACTION_CANCEL" );
break;
}
return true;//return false,会不能触发UP、MOVE操作
}
public interface OnItemTouchListener {
void onItemDown(View view);//当Item按下的时候
void onItemUp(View view);//按下之后,ACTION_UP的时候触发
void onItemMove(View view);
}
三、实现水珠形状ItemView
1、定义ItemView的基本布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@mipmap/bcg_btn_press">
<ImageView
android:id="@+id/item_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/twenty_four_len"
android:layout_gravity="center_horizontal"/>
<TextView
android:id="@+id/item_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textColor="@android:color/white"
android:textSize="@dimen/eighteen_font"
/>
</LinearLayout>
2、实现ItemView
package com.xiaoi.app.robot.view.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.xiaoi.app.robot.R;
/**
* auther: MO
* Date: 2017/1/10
* Time:15:42
* Des:
*/
public class ItemView extends RelativeLayout implements View.OnTouchListener {
private Context context;
private TextView textView;
private ImageView imageView;
private OnItemTouchListener listener;
private int imgId;
private String textId;
public ItemView(Context context) {
super(context);
this.context = context;
}
public ItemView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init(attrs);
}
public ItemView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
init(attrs);
}
private void initAttr(AttributeSet attrs) {
TypedArray types = context.obtainStyledAttributes(attrs,
R.styleable.item_view);
try {
imgId = types.getResourceId(R.styleable.item_view_img_src, R.mipmap.ic_user_btn);
textId = types.getString(R.styleable.item_view_text);
} finally {
types.recycle(); // TypeArray用完需要recycle
}
}
private void init(AttributeSet attrs) {
View contentView = LayoutInflater.from(this.context).inflate(R.layout.item_view, this, true);
imageView = (ImageView) contentView.findViewById(R.id.item_img);
textView = (TextView) contentView.findViewById(R.id.item_txt);
initAttr(attrs);
setImageView(imgId);
textView.setText(textId);
setOnTouchListener(this);
}
public ImageView getImageView(){
return this.imageView;
}
public void setImageView(int resId) {
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId);
imageView.setImageBitmap(bitmap);
}
public void setTextView(String txt){
textView.setText(txt);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
listener.onItemDown(v);
textView.setTextColor(getResources().getColor(android.R.color.holo_blue_dark));
Log.e("TOUCHING", "onTouch: "+"fuckckck onItemDown" );
break;
case MotionEvent.ACTION_MOVE:
listener.onItemMove(v);
break;
case MotionEvent.ACTION_UP:
listener.onItemUp(v);
Log.e("TOUCHING", "onTouch: "+"fuckckck ACTION_UP" );
textView.setTextColor(getResources().getColor(android.R.color.white));
break;
case MotionEvent.ACTION_CANCEL:
Log.e("TOUCHING", "onTouch: "+"fuckckck ACTION_CANCEL" );
break;
}
return true;//return false,会不能触发UP、MOVE操作
}
public void setItemTouchListener(OnItemTouchListener listener) {
this.listener = listener;
}
public interface OnItemTouchListener {
void onItemDown(View view);//当Item按下的时候
void onItemUp(View view);//按下之后,ACTION_UP的时候触发
void onItemMove(View view);
}
}
四、应用水珠形状ItemView
使用起来很简单,我就贴部分代码
布局代码activity_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:crazymo="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/bcg_activity">
<ImageView
android:id="@+id/bcg_light"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:scaleType="centerInside"
android:src="@mipmap/bcg_main" />
<ImageView
android:id="@+id/btn_speak_bgn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:background="@mipmap/voice_01"
android:clickable="true"
android:layout_marginLeft="15dp"
android:visibility="invisible"
android:scaleType="centerInside" />
<ImageView
android:id="@+id/slide_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:clickable="true"
android:src="@drawable/selctor_slide_btn" />
<ImageView
android:id="@+id/btn_speak"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@mipmap/voice_main_default"
android:clickable="true"
android:scaleType="centerInside" />
<com.xiaoi.app.robot.view.widget.ItemView
android:id="@+id/main_user_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="@dimen/one_hundred_len"
crazymo:text="@string/auth" />
<com.xiaoi.app.robot.view.widget.ItemView
android:id="@+id/main_biz_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="@dimen/one_hundred_len"
crazymo:img_src="@mipmap/ic_biz"
crazymo:text="@string/biz" />
<com.xiaoi.app.robot.view.widget.ItemView
android:id="@+id/main_dance_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginLeft="@dimen/one_hundred_len"
crazymo:img_src="@mipmap/ic_dance"
crazymo:text="@string/dance"
/>
<Button
android:id="@+id/main_logout_btn"
android:layout_width="@dimen/senventy_len"
android:layout_height="@dimen/fifty_five_len"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginLeft="@dimen/one_hundred_len"
android:layout_marginBottom="@dimen/thirty_len"
android:background="@mipmap/bcg_btn_press"
android:text="@string/logout"
android:textColor="@color/white"
android:textSize="@dimen/eighteen_font"
android:visibility="visible"
/>
<com.xiaoi.app.robot.view.widget.ItemView
android:id="@+id/main_game_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="@dimen/one_hundred_len"
crazymo:img_src="@mipmap/ic_game"
crazymo:text="@string/game"
/>
</RelativeLayout>
动画xml代码res/animator/animator_menu_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:propertyName="scaleX"
android:valueFrom="0"
android:valueTo="1"
android:duration="1000"
android:interpolator="@android:anim/accelerate_interpolator"
/>
<objectAnimator
android:propertyName="scaleY"
android:valueFrom="0"
android:valueTo="1"
android:duration="1000"
android:interpolator="@android:anim/accelerate_interpolator"
/>
<objectAnimator
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:duration="1000"
android:interpolator="@android:anim/accelerate_interpolator"
/>
</set>
MainActivity.java
public class MainActivity extends BaseActivity implements ItemView.OnItemTouchListener, MainView {
@Bind(R.id.bcg_light)
ImageView bcgLight;
@Bind(R.id.slide_btn)
ImageView slideBtn;
@Bind(R.id.btn_speak)
ImageView btnSpeak;
@Bind(R.id.main_user_content)
ItemView mainUserContent;
@Bind(R.id.main_biz_content)
ItemView mainBizContent;
@Bind(R.id.main_dance_content)
ItemView mainDanceContent;
@Bind(R.id.main_game_content)
ItemView mainGameContent;
private static final String TAG = "MainActivity";
@Bind(R.id.btn_speak_bgn)
ImageView btnSpeakBgn;
@Bind(R.id.main_logout_btn)
Button mainLogoutBtn;
private boolean isShow = false, isVerify = false, isSpeaking = false, needRun = true;
private int startX;
private SlidrConfig config;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int primary = getResources().getColor(R.color.colorPrimaryDark);
int secondary = getResources().getColor(R.color.colorPrimary);
config = new SlidrConfig.Builder()
.primaryColor(primary)
.secondaryColor(secondary)
.position(SlidrPosition.LEFT)
.velocityThreshold(2400)
.distanceThreshold(.25f)
.scrimStartAlpha(0.8f)
.scrimEndAlpha(0f)
.touchSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 32, getResources().getDisplayMetrics()))
.build();
// Attach the Slidr Mechanism to this activity
Slidr.attach(this, config);
ButterKnife.bind(this);
init();
}
private void init() {
setItemViewListen();
showAnmail();
}
@Override
protected void onResume() {
super.onResume();
mainLogoutBtn.setVisibility(View.GONE);
}
/**
* @param v
* @param animator
*/
public void runXmlAnimSet(final View v, final int animator) {
Animator anim = AnimatorInflater.loadAnimator(this, animator);
/*Point center = ScreenUtil.getScreenCenterNoTitle(this);
if (v.getId() == R.id.main_user_content) {
v.setPivotX(center.x);
v.setPivotY(center.y);
} else if (v.getId() == R.id.main_biz_content) {
v.setPivotX(-center.x);
v.setPivotY(center.y);
} else if (v.getId() == R.id.main_dance_content) {
v.setPivotX(center.x);
v.setPivotY(-center.y);
} else if (v.getId() == R.id.main_game_content) {
v.setPivotX(-center.x);
v.setPivotY(-center.y);
}*/
anim.setTarget(v);
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
if (animator == R.animator.animator_menu_in) {
v.setVisibility(View.VISIBLE);
}
}
@Override
public void onAnimationEnd(Animator animation) {
if (animator == R.animator.animator_menu_out) {
v.setVisibility(View.GONE);
}
}
@Override
public void onAnimationCancel(Animator animation) {
return;
}
@Override
public void onAnimationRepeat(Animator animation) {
return;
}
});
anim.start();
}
private void setItemViewListen() {
mainUserContent.setItemTouchListener(this);
mainBizContent.setItemTouchListener(this);
mainDanceContent.setItemTouchListener(this);
mainGameContent.setItemTouchListener(this);
}
private void setTouchListen() {
bcgLight.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int endX = (int) event.getX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) event.getX();
Log.e("TOUCHING", "onTouch: startX" + startX + "startX" + startX);
break;
case MotionEvent.ACTION_MOVE:
//向右滑动超过50px
if (endX - startX > 50) {
startVoiceActivity();
Toast.makeText(MainActivity.this, "**Moving to RIght** ", Toast.LENGTH_SHORT).show();
} else if (startX - endX > 50) {
Log.e("TOUCHING", "onTouch:ACTION_MOVE endX" + endX + "startX:" + startX);
Toast.makeText(MainActivity.this, "**Moving to Left** ", Toast.LENGTH_SHORT).show();
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return false;
}
});
mainLogoutBtn.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
logout();
mainLogoutBtn.setTextColor(getResources().getColor(android.R.color.holo_blue_dark));
break;
case MotionEvent.ACTION_UP:
mainLogoutBtn.setTextColor(getResources().getColor(android.R.color.white));
mainLogoutBtn.setVisibility(View.GONE);
break;
default:
break;
}
return false;
}
});
}
private void setPressBackground(View view) {
switch (view.getId()) {
case R.id.main_user_content:
if (isVerify) {
mainUserContent.setImageView(R.mipmap.ic_user_btn_press);
} else {
mainUserContent.getImageView().setImageBitmap(bitmap);
}
break;
case R.id.main_biz_content:
mainBizContent.setImageView(R.mipmap.ic_biz_press);
break;
case R.id.main_dance_content:
mainDanceContent.setImageView(R.mipmap.ic_dance_press);
break;
case R.id.main_game_content:
mainGameContent.setImageView(R.mipmap.ic_game_press);
break;
default:
break;
}
}
private void setNormalBackground(View view) {
switch (view.getId()) {
case R.id.main_user_content:
if (isVerify) {
mainUserContent.setImageView(R.mipmap.ic_user_btn);
} else {
mainUserContent.getImageView().setImageBitmap(bitmap);
}
break;
case R.id.main_biz_content:
mainBizContent.setImageView(R.mipmap.ic_biz);
break;
case R.id.main_dance_content:
mainDanceContent.setImageView(R.mipmap.ic_dance);
break;
case R.id.main_game_content:
mainGameContent.setImageView(R.mipmap.ic_game);
break;
default:
break;
}
}
private void verifyFace() {
}
private void openBiz() {
}
private void showDance() {
startActivity(new Intent(this,DanceActivity.class));
overridePendingTransition(R.anim.enter_left_to_right, R.anim.back_right_to_left);
}
private void palyGame() {
}
@OnClick({R.id.slide_btn, R.id.btn_speak, R.id.bcg_light})
void onClick(View view) {
switch (view.getId()) {
case R.id.slide_btn:
openSlide();
break;
case R.id.bcg_light:
showMenu();
break;
case R.id.btn_speak:
startSpeak();
break;
default:
break;
}
}
private void openSlide() {
startVoiceActivity();
}
private void startSpeak() {
requestionPermission();
}
private void showMenu() {
if (isShow) {
hideAnmail();
} else {
showAnmail();
}
}
//隐藏动画
private void hideAnmail() {
runXmlAnimSet(mainUserContent, R.animator.animator_menu_out);
runXmlAnimSet(mainBizContent, R.animator.animator_menu_out);
runXmlAnimSet(mainDanceContent, R.animator.animator_menu_out);
runXmlAnimSet(mainGameContent, R.animator.animator_menu_out);
isShow = false;
}
//显示动画
private void showAnmail() {
runXmlAnimSet(mainUserContent, R.animator.animator_menu_in);
runXmlAnimSet(mainBizContent, R.animator.animator_menu_in);
runXmlAnimSet(mainDanceContent, R.animator.animator_menu_in);
runXmlAnimSet(mainGameContent, R.animator.animator_menu_in);
isShow = true;
}
public void logout() {
Toast.makeText(this, "**注销** ", Toast.LENGTH_SHORT).show();
mainUserContent.setImageView(R.mipmap.ic_user_btn);
mainUserContent.setTextView("身份注册");
isVerify = false;
}
@Override
public void onItemDown(View view) {
setPressBackground(view);
switch (view.getId()) {
case R.id.main_user_content:
verifyFace();
break;
case R.id.main_biz_content:
openBiz();
break;
case R.id.main_dance_content:
showDance();
break;
case R.id.main_game_content:
palyGame();
break;
default:
break;
}
}
@Override
public void onItemUp(View view) {
setNormalBackground(view);
}
@Override
public void onItemMove(View view) {
return;
}
@Override
protected void onDestroy() {
super.onDestroy();
voiceUtil.onDestroy(false);
}
}