Android进阶——自定义View之组合系统控件实现水珠形状的ItemView

引言

相信大家在项目开发的过程中一定会有不少需要在上方显示一张图片,而在其下方显示提示标题的效果,作为一个界面的功能按钮或者单纯作为一个列表的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);
    }
}

这里写图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CrazyMo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值