仿今日头条“关注”按钮的实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010724819/article/details/75225209

首先来看下今日头条效果图:


再来看下我们实现的效果:



实现思路,为了复用以及封装性,所以决定使用自定义ViewGroup来实现,下面来看实现代码:

这里是初始化布局,以及监听事件的方法:

  /**
     * 初始化布局
     */
    private void initView() {
        //获取外布局的宽高
        int totalWidth = getMeasuredWidth();
        int totalHeight = getMeasuredHeight();
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child instanceof Button) {
                button = (Button) getChildAt(i);
                //摆放子View,参数分别是子View矩形区域的左、上、右、下边
                child.layout(0, 0, totalWidth, totalHeight);
            }
            if (getChildAt(i) instanceof ProgressBar) {
                progressBar = (ProgressBar) getChildAt(i);
                //摆放子View,参数分别是子View矩形区域的左、上、右、下边
                child.layout(0, 0, totalWidth, totalHeight);
            }
        }

        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if ("已关注".equals(button.getText().toString().trim())) {
                    return;
                }

                Message message = Message.obtain();
                message.obj = "";
                message.what = 2;
                handler.sendMessage(message);

                if (buttonClickListener != null) {
                    buttonClickListener.innerClick();
                }
            }
        });
    }


根据instanceOf方法来判别当前 找到控件是哪个,然后进行layout,这里有个坑,如果使用强转之后的View(例如:Button)来进行layout设置,是不起作用的,必须使用直接找到的ChildView来进行安放位置。

好了,其实这里开始还考虑到使用代码动态创建View然后layout上去,后来发现,这样的话需要定义许多的自定义属性,索性就不用代码动态添加了,哈哈,偷懒了!

有两种状态,一种是关注成功,一种是关注失败,这两个设定都是通过暴露方法之后在MainActivity中进行实现的。

下面来看代码:

    //完成方法
    public void setOnInnerFinish(String text) {
        Message message = Message.obtain();
        message.obj = text;
        message.what = 1;
        handler.sendMessage(message);
    }

    //失败完成方法
    public void setOnInnerUnFinish(final String text) {
        Message message = Message.obtain();
        message.obj = text;
        message.what = 0;
        handler.sendMessage(message);
    }

这里有个问题,就是之前在写代码的时候,progressBar的setVisivility(View.GONE)没有任何效果,之后,我才发现烦了低级错误。。。

应该在UI线程刷新控件:

 private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    progressBar.clearAnimation();
                    progressBar.setVisibility(View.GONE);
                    button.setTextColor(getResources().getColor(R.color.colorWhite));
                    button.setText(msg.obj.toString());
                    button.setBackgroundResource(R.drawable.unclickshape);
                    Toast.makeText(context, "关注失败!", Toast.LENGTH_SHORT).show();
                    break;
                case 1:
                    progressBar.setVisibility(View.GONE);
                    button.setTextColor(getResources().getColor(R.color.colorBlack));
                    button.setText(msg.obj.toString());
                    button.setBackgroundResource(R.drawable.clickshape);
                    Toast.makeText(context, "关注成功!", Toast.LENGTH_SHORT).show();
                    break;
                case 2:
                    //设定按钮颜色以及进度条可见性
                    progressBar.setVisibility(View.VISIBLE);
                    button.setText(msg.obj.toString());
                    break;
            }

完整布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context="com.marsjiang.mystatebutton.MainActivity">

    <com.marsjiang.mystatebutton.MyStateButton
        android:id="@+id/mystatebar"
        android:layout_width="200dp"
        android:layout_height="50dp">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <Button
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/unclickshape"
                android:text="关注"
                android:textColor="@color/colorWhite"/>
        </RelativeLayout>

        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:indeterminateBehavior="repeat"
            android:indeterminateDrawable="@drawable/dialog_loading"
            android:indeterminateOnly="true"
            android:visibility="gone"/>

    </com.marsjiang.mystatebutton.MyStateButton>


完整的代码如下:

/**
 * 自定义多种状态的按钮
 * Created by Jiang on 2017-07-15.
 */

public class MyStateButton extends RelativeLayout {
    private Context context;
    private Button button;
    private ProgressBar progressBar;
    private ButtonClickListener buttonClickListener;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    progressBar.clearAnimation();
                    progressBar.setVisibility(View.GONE);
                    button.setTextColor(getResources().getColor(R.color.colorWhite));
                    button.setText(msg.obj.toString());
                    button.setBackgroundResource(R.drawable.unclickshape);
                    Toast.makeText(context, "关注失败!", Toast.LENGTH_SHORT).show();
                    break;
                case 1:
                    progressBar.setVisibility(View.GONE);
                    button.setTextColor(getResources().getColor(R.color.colorBlack));
                    button.setText(msg.obj.toString());
                    button.setBackgroundResource(R.drawable.clickshape);
                    Toast.makeText(context, "关注成功!", Toast.LENGTH_SHORT).show();
                    break;
                case 2:
                    //设定按钮颜色以及进度条可见性
                    progressBar.setVisibility(View.VISIBLE);
                    button.setText(msg.obj.toString());
                    break;
            }
        }
    };

    public interface ButtonClickListener {
        void innerClick();
    }

    //点击监听
    public void setOnInnerClickeListener(ButtonClickListener buttonClickListener) {
        this.buttonClickListener = buttonClickListener;
    }

    //完成方法
    public void setOnInnerFinish(String text) {
        Message message = Message.obtain();
        message.obj = text;
        message.what = 1;
        handler.sendMessage(message);
    }

    //失败完成方法
    public void setOnInnerUnFinish(final String text) {
        Message message = Message.obtain();
        message.obj = text;
        message.what = 0;
        handler.sendMessage(message);
    }

    public MyStateButton(Context context) {
        super(context);
        this.context = context;
    }

    public MyStateButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

    public MyStateButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
    }

    /**
     * 初始化布局
     */
    private void initView() {
        //获取外布局的宽高
        int totalWidth = getMeasuredWidth();
        int totalHeight = getMeasuredHeight();
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child instanceof Button) {
                button = (Button) getChildAt(i);
                //摆放子View,参数分别是子View矩形区域的左、上、右、下边
                child.layout(0, 0, totalWidth, totalHeight);
            }
            if (getChildAt(i) instanceof ProgressBar) {
                progressBar = (ProgressBar) getChildAt(i);
                //摆放子View,参数分别是子View矩形区域的左、上、右、下边
                child.layout(0, 0, totalWidth, totalHeight);
            }
        }

        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if ("已关注".equals(button.getText().toString().trim())) {
                    return;
                }

                Message message = Message.obtain();
                message.obj = "";
                message.what = 2;
                handler.sendMessage(message);

                if (buttonClickListener != null) {
                    buttonClickListener.innerClick();
                }
            }
        });
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        for (int i = 0; i < getChildCount(); i++) {
            View childView = getChildAt(i);
            int a = childView.getMeasuredWidth();
            int b = childView.getMeasuredHeight();
        }

        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
//        super.onLayout(changed, l, t, r, b);
        initView();
    }
}

MainActivity中的设定代码如下:

public class MainActivity extends AppCompatActivity {
    private MyStateButton myStateButton;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
//              myStateButton.setOnInnerUnFinish("关注");
            myStateButton.setOnInnerFinish("已关注");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myStateButton = (MyStateButton) findViewById(R.id.mystatebar);
        myStateButton.setOnInnerClickeListener(new MyStateButton.ButtonClickListener() {
            @Override
            public void innerClick() {
                Message msg = Message.obtain();
                handler.sendMessageDelayed(msg,2000);
            }
        });
    }
}

这里有个小小的问题,在我的安卓4.4手机上可以正常运行,但是在安卓7.0的手机上运行,展示不出来进度条,第一次写自定义控件的开源项目,希望大家多多包涵啊!

终于解决了,参考了点击打开链接文章,在布局文件里面,给Button套了一层布局:

   <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <Button
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/unclickshape"
                android:text="关注"
                android:textColor="@color/colorWhite"/>
        </RelativeLayout>


代码里面获取的时候也有点问题,修改如下:

  if (child instanceof RelativeLayout) {
                button = (Button) ((RelativeLayout) child).getChildAt(0);
//                button = (Button) getChildAt(i);
                //摆放子View,参数分别是子View矩形区域的左、上、右、下边
                child.layout(0, 0, totalWidth, totalHeight);
            }
            if (getChildAt(i) instanceof ProgressBar) {
                progressBar = (ProgressBar) getChildAt(i);
                //摆放子View,参数分别是子View矩形区域的左、上、右、下边
                child.layout(0, 0, totalWidth, totalHeight);
            }
        }

吐舌头好开心啊!

源码地址:

MyStateButton

猜你喜欢

转载自blog.csdn.net/u010724819/article/details/75225209