布局文件:activity_main.xml
<?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:orientation="vertical" tools:context=".view.activitys.MainActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="56dp" android:background="@android:color/holo_red_light" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:gravity="center" android:text="购物车" android:padding="5dp" /> </RelativeLayout> <ExpandableListView android:id="@+id/shopexpand" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="8" android:layout_marginLeft="10dp" android:groupIndicator="@null" > </ExpandableListView> <LinearLayout android:layout_width="match_parent" android:layout_height="65dp" android:layout_alignParentBottom="true" android:gravity="center_vertical" > <com.example.zer.text01.view.activitys.SmoothCheckBox android:id="@+id/checkAll" android:layout_width="24dp" android:layout_height="24dp" android:layout_marginLeft="15dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:text="全选/反选" android:textColor="#333333" android:textSize="15sp" /> <TextView android:id="@+id/total_price" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="50dp" android:textSize="20sp" android:textColor="#e53e42" android:text="总价 : ¥0元" android:gravity="center" /> <TextView android:id="@+id/total_count" android:gravity="center" android:textSize="24dp" android:text="去结算" android:layout_marginLeft="100dp" android:textColor="@android:color/black" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#f00"/> </LinearLayout> </LinearLayout>
---------------------------------------------------------------------------------------------------------------------------
二级列表的父布局文件:groupview.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="match_parent" android:paddingTop="20dp" android:paddingBottom="20dp"> <com.example.zer.text01.view.activitys.SmoothCheckBox android:id="@+id/cb_group" android:layout_width="24dp" android:layout_height="24dp" android:layout_gravity="center_vertical" /> <ImageView android:layout_width="50dp" android:layout_height="50dp" android:scaleType="centerCrop" android:background="@mipmap/dianpu" android:layout_marginLeft="15dp" android:layout_gravity="center_vertical" /> <TextView android:id="@+id/group_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="15dp" android:layout_gravity="center_vertical" android:textSize="14sp" /> </LinearLayout>
----------------------------------------------------------------------------------------------------------------
二级列表的子布局文件:childview.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="match_parent" android:paddingLeft="30dp"> <com.example.zer.text01.view.activitys.SmoothCheckBox android:id="@+id/cb_child" android:layout_width="24dp" android:layout_height="24dp" android:layout_gravity="center_vertical" /> <ImageView android:id="@+id/child_img" android:layout_width="80dp" android:layout_height="80dp" android:scaleType="fitXY" android:layout_gravity="center_vertical" android:layout_marginLeft="10dp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_gravity="center_vertical" android:layout_marginLeft="10dp" > <TextView android:id="@+id/child_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="false" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" > <TextView android:id="@+id/child_price" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="59.90" android:textColor="@android:color/holo_red_light" /> <com.example.zer.text01.view.activitys.CustomChangeNumView android:id="@+id/custom" android:layout_width="wrap_content" android:layout_height="wrap_content"> </com.example.zer.text01.view.activitys.CustomChangeNumView> <ImageView android:id="@+id/child_rublish" android:layout_width="50dp" android:layout_height="50dp" android:background="@mipmap/rublish" android:layout_gravity="center_vertical" android:layout_marginLeft="15dp" /> </LinearLayout> </LinearLayout> </LinearLayout>
------------------------------------------------------------------------------------------------------------------
自定义view的布局文件:changeview.xml(加减号)
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" > <Button android:background="#fff" android:textSize="20sp" android:id="@+id/child_reverse" android:text="一" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <EditText android:textStyle="bold" android:textSize="23sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/child_reverse" android:id="@+id/child_count" /> <Button android:id="@+id/child_add" android:background="#fff" android:textSize="25sp" android:text="+" android:layout_toRightOf="@id/child_count" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
-----------------------------------------------------------------------------------------------------------------
Mainactivity中:
package com.example.zer.text01.view.activitys; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.ExpandableListView; import android.widget.TextView; import com.example.zer.text01.Base.BaseActivity; import com.example.zer.text01.R; import com.example.zer.text01.model.bean.ResultBean; import com.example.zer.text01.presenter.MainPresenter; import com.example.zer.text01.view.IMainView; import com.example.zer.text01.view.adapters.MyExpandAdapter; import com.example.zer.text01.view.interfaces.UpdateView; import java.util.HashMap; import java.util.Map; public class MainActivity extends BaseActivity<MainPresenter> implements IMainView,UpdateView { private String url="https://www.zhaoapi.cn/product/getCarts"; private Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); ResultBean resultBean= (ResultBean) msg.obj; setAdapter(resultBean); } }; private MyExpandAdapter adapter; public void setAdapter(ResultBean resultBean){ adapter = new MyExpandAdapter(MainActivity.this); adapter.setData(resultBean); adapter.setUpdateViewListener(this); shopExapnd.setAdapter(adapter); for (int i=0;i<resultBean.getData().size();i++){ shopExapnd.expandGroup(i); }; } private ExpandableListView shopExapnd; private SmoothCheckBox checkAll; private TextView total_price; private TextView total_count; @Override protected void initListener() { checkAll.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { checkAll.setChecked(!checkAll.isChecked()); adapter.selectAll(checkAll.isChecked()); } }); } @Override protected void initData() { Map<String,String> parms=new HashMap<>(); parms.put("uid","13850"); getBasePresenter().getDataFromServer(url,parms); } @Override protected MainPresenter initPresenter() { return new MainPresenter(); } @Override protected void initView() { //二级列表 shopExapnd = findViewById(R.id.shopexpand); //全选/反选按钮 checkAll = findViewById(R.id.checkAll); //总价格 total_price = findViewById(R.id.total_price); //总数量 total_count = findViewById(R.id.total_count); } @Override protected int getActivityLayout() { return R.layout.activity_main; } @Override public void getBackData(ResultBean resultBean) { Message msg=Message.obtain(); msg.obj=resultBean; handler.sendMessage(msg); } //更新的方法 @Override public void update(boolean isAllSelected, int count, float price) { checkAll.setChecked(isAllSelected); total_count.setText("结算"+count); total_price.setText("¥"+price); } }
-------------------------------------------------------------------------------------------------------------------
MainPresenter:
package com.example.zer.text01.presenter; import com.example.zer.text01.model.bean.ResultBean; import com.example.zer.text01.model.net.MainMoudle; import com.example.zer.text01.view.IMainView; import java.util.Map; public class MainPresenter extends BasePresenter<IMainView> implements DataBack{ private MainMoudle mainMoudle; public MainPresenter() { this.mainMoudle = new MainMoudle(); } public void getDataFromServer(String url, Map<String,String> parms){ mainMoudle.getShopCarData(url,parms,this); } @Override public void callbackSuccess(ResultBean resultBean) { getBaseView().getBackData(resultBean); } @Override public void callbackFailed(String msg) { } }
----------------------------------------------------------------------------------------------
基类BaseActivity:
package com.example.zer.text01.Base; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import com.example.zer.text01.presenter.BasePresenter; import com.example.zer.text01.view.interfaces.BaseView; public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements BaseView { private P basePresenter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getActivityLayout()); initView(); basePresenter=initPresenter(); basePresenter.attachView(this); initData(); initListener(); } protected P getBasePresenter(){ return basePresenter; } protected abstract void initListener(); protected abstract void initData(); protected abstract P initPresenter(); protected abstract void initView(); protected abstract int getActivityLayout(); }
---------------------------------------------------------------------------------------------------------------------
基类的Presenter:BasePresenter:
package com.example.zer.text01.presenter; import com.example.zer.text01.view.interfaces.BaseView; public class BasePresenter<V extends BaseView> { private V baseView; public void attachView(V baseView){ this.baseView=baseView; } public void detachView(){ if(this.baseView!=null){ this.baseView=null; } } public V getBaseView(){ return this.baseView; } }
-----------------------------------------------------------------------------------------------------------------
适配器:MyExpandAdapter:
package com.example.zer.text01.view.adapters; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; import com.example.zer.text01.R; import com.example.zer.text01.model.bean.ResultBean; import com.example.zer.text01.view.activitys.CustomChangeNumView; import com.example.zer.text01.view.activitys.SmoothCheckBox; import com.example.zer.text01.view.interfaces.UpdateView; public class MyExpandAdapter extends BaseExpandableListAdapter implements View.OnClickListener { private ResultBean resultBean; private Context context; private UpdateView updateViewListener; public MyExpandAdapter(Context context) { this.context = context; } //设置数据 public void setData(ResultBean rBean){ this.resultBean=rBean; } @Override public int getGroupCount() { return resultBean.getData().size(); } @Override public int getChildrenCount(int groupPosition) { return resultBean.getData().get(groupPosition).getList().size(); } @Override public Object getGroup(int groupPosition) { return resultBean.getData().get(groupPosition); } @Override public Object getChild(int groupPosition, int childPosition) { return resultBean.getData().get(groupPosition).getList().get(childPosition); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public long getChildId(int groupPosition, int childPosition) { return childPosition; } @Override public boolean hasStableIds() { return false; } //组 @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { GroupViewHolder groupViewHolder; if(convertView==null){ convertView= LayoutInflater.from(context).inflate(R.layout.groupview,parent,false); groupViewHolder=new GroupViewHolder(convertView); convertView.setTag(groupViewHolder); }else{ groupViewHolder= (GroupViewHolder) convertView.getTag(); } groupViewHolder.group_name.setText(resultBean.getData().get(groupPosition).getSellerName()); //设置tag groupViewHolder.cb_group.setTag(groupPosition); //设置group复选框的点击事件 groupViewHolder.cb_group.setOnClickListener(this); //根据获取到的复选框状态设置是否被选中 if(resultBean.getData().get(groupPosition).getGroupSelect()){ if(!groupViewHolder.cb_group.isChecked()){ groupViewHolder.cb_group.setChecked(true); } }else{ groupViewHolder.cb_group.setChecked(false); } return convertView; } @Override public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { final ChildViewHolder childViewHolder; if(convertView==null){ convertView=LayoutInflater.from(context).inflate(R.layout.childview,parent,false); childViewHolder=new ChildViewHolder(convertView); convertView.setTag(childViewHolder); }else{ childViewHolder= (ChildViewHolder) convertView.getTag(); } //设置child的tag String tag = groupPosition + "," + childPosition; childViewHolder.cb_child.setTag(tag); childViewHolder.child_rublish.setTag(tag); //设置child复选框的点击事件 childViewHolder.child_rublish.setOnClickListener(this); childViewHolder.cb_child.setOnClickListener(this); childViewHolder.customChangeNumView.setEditText(resultBean.getData().get(groupPosition).getList().get(childPosition).getNum()); //加减监听 childViewHolder.customChangeNumView.setCustomListener(new CustomChangeNumView.CustomListener() { @Override public void jiajian(int count) { resultBean.getData().get(groupPosition).getList().get(childPosition).setNum(count); notifyDataSetChanged(); sumList(resultBean); } }); //根据获取的状态设置是否选中 if(resultBean.getData().get(groupPosition).getList().get(childPosition).getChildSelect()){ childViewHolder.cb_child.setChecked(true); }else{ childViewHolder.cb_child.setChecked(false); } // childViewHolder.child_img.setTag(tag); if(resultBean.getData().get(groupPosition).getList().get(childPosition).getImages().split("\\|").length>0) { Glide.with(context).load(resultBean.getData().get(groupPosition).getList().get(childPosition).getImages().split("\\|")[0]).into(childViewHolder.child_img); }else{ Glide.with(context).load(resultBean.getData().get(groupPosition).getList().get(childPosition).getImages()).into(childViewHolder.child_img); } childViewHolder.child_title.setText(resultBean.getData().get(groupPosition).getList().get(childPosition).getTitle()+""); childViewHolder.child_price.setText(resultBean.getData().get(groupPosition).getList().get(childPosition).getPrice()+""); return convertView; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } //的viewholder class GroupViewHolder{ SmoothCheckBox cb_group; TextView group_name; public GroupViewHolder(View itemView) { cb_group=itemView.findViewById(R.id.cb_group); group_name=itemView.findViewById(R.id.group_name); } } //child的viewholdergroup class ChildViewHolder{ SmoothCheckBox cb_child; ImageView child_img; ImageView child_rublish; TextView child_title; TextView child_price; CustomChangeNumView customChangeNumView; public ChildViewHolder(View itemView) { cb_child=itemView.findViewById(R.id.cb_child); child_img=itemView.findViewById(R.id.child_img); child_title=itemView.findViewById(R.id.child_title); child_price=itemView.findViewById(R.id.child_price); child_rublish=itemView.findViewById(R.id.child_rublish); customChangeNumView=itemView.findViewById(R.id.custom); } } //点击事件 @Override public void onClick(View v) { SmoothCheckBox checkBox; String tag = v.getTag().toString(); String[] split; int groupId = 0; int childId = 0; int childSize = 0; int groupPosition = 0; if(tag.contains(",")){ split = tag.split(","); groupId=Integer.valueOf(split[0]); childId=Integer.valueOf(split[1]); }else{ groupPosition=Integer.valueOf(tag); childSize=resultBean.getData().get(groupPosition).getList().size(); } switch (v.getId()){ //组的复选框点击 case R.id.cb_group: checkBox= (SmoothCheckBox) v; resultBean.getData().get(groupPosition).setGroupSelect(!checkBox.isChecked()); if(!checkBox.isChecked()){ for (int i=0;i<childSize;i++){ if(!resultBean.getData().get(groupPosition).getList().get(i).getChildSelect()){ resultBean.getData().get(groupPosition).getList().get(i).setChildSelect(!checkBox.isChecked()); } } }else{ for (int i=0;i<childSize;i++){ resultBean.getData().get(groupPosition).getList().get(i).setChildSelect(!checkBox.isChecked()); } } int fCount=0; for (int i=0;i<resultBean.getData().size();i++){ if(resultBean.getData().get(i).getGroupSelect()){ fCount++; } } if(fCount==resultBean.getData().size()){ resultBean.setAllSelect(true); }else{ resultBean.setAllSelect(false); } sumList(resultBean); notifyDataSetChanged(); break; case R.id.cb_child: checkBox= (SmoothCheckBox) v; int cCount=0; int gCount=0; resultBean.getData().get(groupId).getList().get(childId).setChildSelect(!checkBox.isChecked()); for (int i=0;i<resultBean.getData().get(groupId).getList().size();i++){ if(resultBean.getData().get(groupId).getList().get(i).getChildSelect()){ cCount++; } } if(cCount==resultBean.getData().get(groupId).getList().size()){ resultBean.getData().get(groupId).setGroupSelect(true); }else{ resultBean.getData().get(groupId).setGroupSelect(false); } for (int i=0;i<resultBean.getData().size();i++){ if(resultBean.getData().get(i).getGroupSelect()){ gCount++; } } if(gCount==resultBean.getData().size()){ resultBean.setAllSelect(true); }else{ resultBean.setAllSelect(false); } sumList(resultBean); notifyDataSetChanged(); break; case R.id.child_rublish: resultBean.getData().get(groupId).getList().remove(childId); if(resultBean.getData().get(groupId).getList().size()==0){ resultBean.getData().remove(groupId); } sumList(resultBean); notifyDataSetChanged(); break; } } //设置updateviewlistener public void setUpdateViewListener(UpdateView Listener){ if(updateViewListener==null){ this.updateViewListener=Listener; } } //计算总价的 public void sumList(ResultBean resultBean){ int allCount=0; float allMoney=0; for (int i=0;i<resultBean.getData().size();i++){ for(int j=0;j<resultBean.getData().get(i).getList().size();j++){ if(resultBean.getData().get(i).getList().get(j).getChildSelect()){ allCount+=resultBean.getData().get(i).getList().get(j).getNum(); allMoney+=resultBean.getData().get(i).getList().get(j).getNum()*resultBean.getData().get(i).getList().get(j).getPrice(); } } } resultBean.setAllCount(allCount); resultBean.setAllMoney(allMoney); updateViewListener.update(resultBean.getAllSelect(),allCount,allMoney); } //全选 public void selectAll(boolean checked){ resultBean.setAllSelect(checked); for (int i=0;i<resultBean.getData().size();i++){ resultBean.getData().get(i).setGroupSelect(checked); for (int j=0;j<resultBean.getData().get(i).getList().size();j++){ resultBean.getData().get(i).getList().get(j).setChildSelect(checked); } } notifyDataSetChanged(); sumList(resultBean); } }
MainActivity的接口:IMainView:
public interface IMainView extends BaseView { void getBackData(ResultBean resultBean); }
基类的接口(BaseView)没有任何东西,在这里就不写啦^_^
--------------------------------------------------------------------------------------------------------------
UpdateView:
package com.example.zer.text01.view.interfaces; public interface UpdateView { void update(boolean isAllSelected, int count, float price); }
------------------------------------------------------------------------------------------------------
自定义view:CustomChangeNumView
package com.example.zer.text01.view.activitys; import android.content.Context; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.RelativeLayout; import com.example.zer.text01.R; public class CustomChangeNumView extends RelativeLayout{ private Button reverse; private Button add; private EditText countEdit; private CustomListener customListener; public CustomChangeNumView(Context context) { super(context); initView(context); } public CustomChangeNumView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initView(context); } public CustomChangeNumView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } public void initView(Context context) { View view= View.inflate(context, R.layout.changeview,null); reverse = (Button) view.findViewById(R.id.child_reverse); add = (Button) view.findViewById(R.id.child_add); countEdit = (EditText) view.findViewById(R.id.child_count); //减的时候回调 reverse.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int count = Integer.valueOf(countEdit.getText().toString()); if(count>1){ count--; countEdit.setText(count+""); if(customListener!=null){ customListener.jiajian(count); } } } }); //加的时候回调 add.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int count = Integer.valueOf(countEdit.getText().toString()); count++; countEdit.setText(count+""); if(customListener!=null){ customListener.jiajian(count); } } }); this.addView(view); } //设置接口 public interface CustomListener{ void jiajian(int count); } //设置回调方法 public void setCustomListener(CustomListener customListener){ this.customListener=customListener; } public void setEditText(int num) { if(countEdit !=null) { countEdit.setText(num + ""); } } }
-----------------------------------------------------------------------------------------------------
组合控件:SmoothCheckBox(复选框)
package com.example.zer.text01.view.activitys; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Path; import android.os.Bundle; import android.os.Parcelable; import android.util.AttributeSet; import android.view.View; import android.view.animation.LinearInterpolator; import android.widget.Checkable; import com.example.zer.text01.R; import com.example.zer.text01.util.TextSizeUtils; public class SmoothCheckBox extends View implements Checkable { private static final String KEY_INSTANCE_STATE = "InstanceState"; private static final int COLOR_TICK = Color.WHITE; private static final int COLOR_UNCHECKED = Color.WHITE; private static final int COLOR_CHECKED = Color.parseColor("#FB4846"); private static final int COLOR_FLOOR_UNCHECKED = Color.parseColor("#DFDFDF"); private static final int DEF_DRAW_SIZE = 25; private static final int DEF_ANIM_DURATION = 300; private Paint mPaint, mTickPaint, mFloorPaint; private Point[] mTickPoints; private Point mCenterPoint; private Path mTickPath; private float mLeftLineDistance, mRightLineDistance, mDrewDistance; private float mScaleVal = 1.0f, mFloorScale = 1.0f; private int mWidth, mAnimDuration, mStrokeWidth; private int mCheckedColor, mUnCheckedColor, mFloorColor, mFloorUnCheckedColor; private boolean mChecked; private boolean mTickDrawing; private OnCheckedChangeListener mListener; public SmoothCheckBox(Context context) { this(context, null); } public SmoothCheckBox(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SmoothCheckBox(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } private void init(AttributeSet attrs) { TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.SmoothCheckBox); int tickColor = ta.getColor(R.styleable.SmoothCheckBox_color_tick, COLOR_TICK); mAnimDuration = ta.getInt(R.styleable.SmoothCheckBox_duration, DEF_ANIM_DURATION); mFloorColor = ta.getColor(R.styleable.SmoothCheckBox_color_unchecked_stroke, COLOR_FLOOR_UNCHECKED); mCheckedColor = ta.getColor(R.styleable.SmoothCheckBox_color_checked, COLOR_CHECKED); mUnCheckedColor = ta.getColor(R.styleable.SmoothCheckBox_color_unchecked, COLOR_UNCHECKED); mStrokeWidth = ta.getDimensionPixelSize(R.styleable.SmoothCheckBox_stroke_width, TextSizeUtils.dip2px(getContext(), 0)); ta.recycle(); mFloorUnCheckedColor = mFloorColor; mTickPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTickPaint.setStyle(Paint.Style.STROKE); mTickPaint.setStrokeCap(Paint.Cap.ROUND); mTickPaint.setColor(tickColor); mFloorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mFloorPaint.setStyle(Paint.Style.FILL); mFloorPaint.setColor(mFloorColor); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(mCheckedColor); mTickPath = new Path(); mCenterPoint = new Point(); mTickPoints = new Point[3]; mTickPoints[0] = new Point(); mTickPoints[1] = new Point(); mTickPoints[2] = new Point(); setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { toggle(); mTickDrawing = false; mDrewDistance = 0; if (isChecked()) { startCheckedAnimation(); } else { startUnCheckedAnimation(); } } }); } @Override protected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); bundle.putParcelable(KEY_INSTANCE_STATE, super.onSaveInstanceState()); bundle.putBoolean(KEY_INSTANCE_STATE, isChecked()); return bundle; } @Override protected void onRestoreInstanceState(Parcelable state) { if (state instanceof Bundle) { Bundle bundle = (Bundle) state; boolean isChecked = bundle.getBoolean(KEY_INSTANCE_STATE); setChecked(isChecked); super.onRestoreInstanceState(bundle.getParcelable(KEY_INSTANCE_STATE)); return; } super.onRestoreInstanceState(state); } @Override public boolean isChecked() { return mChecked; } @Override public void toggle() { this.setChecked(!isChecked()); } @Override public void setChecked(boolean checked) { mChecked = checked; reset(); invalidate(); if (mListener != null) { mListener.onCheckedChanged(SmoothCheckBox.this, mChecked); } } /** * checked with animation * * @param checked checked * @param animate change with animation */ public void setChecked(boolean checked, boolean animate) { if (animate) { mTickDrawing = false; mChecked = checked; mDrewDistance = 0f; if (checked) { startCheckedAnimation(); } else { startUnCheckedAnimation(); } if (mListener != null) { mListener.onCheckedChanged(SmoothCheckBox.this, mChecked); } } else { this.setChecked(checked); } } private void reset() { mTickDrawing = true; mFloorScale = 1.0f; mScaleVal = isChecked() ? 0f : 1.0f; mFloorColor = isChecked() ? mCheckedColor : mFloorUnCheckedColor; mDrewDistance = isChecked() ? (mLeftLineDistance + mRightLineDistance) : 0; } private int measureSize(int measureSpec) { int defSize = TextSizeUtils.dip2px(getContext(), DEF_DRAW_SIZE); int specSize = MeasureSpec.getSize(measureSpec); int specMode = MeasureSpec.getMode(measureSpec); int result = 0; switch (specMode) { case MeasureSpec.UNSPECIFIED: case MeasureSpec.AT_MOST: result = Math.min(defSize, specSize); break; case MeasureSpec.EXACTLY: result = specSize; break; } return result; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(measureSize(widthMeasureSpec), measureSize(heightMeasureSpec)); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { mWidth = getMeasuredWidth(); mStrokeWidth = (mStrokeWidth == 0 ? getMeasuredWidth() / 10 : mStrokeWidth); mStrokeWidth = mStrokeWidth > getMeasuredWidth() / 5 ? getMeasuredWidth() / 5 : mStrokeWidth; mStrokeWidth = (mStrokeWidth < 3) ? 3 : mStrokeWidth; mCenterPoint.x = mWidth / 2; mCenterPoint.y = getMeasuredHeight() / 2; mTickPoints[0].x = Math.round((float) getMeasuredWidth() / 30 * 7); mTickPoints[0].y = Math.round((float) getMeasuredHeight() / 30 * 14); mTickPoints[1].x = Math.round((float) getMeasuredWidth() / 30 * 13); mTickPoints[1].y = Math.round((float) getMeasuredHeight() / 30 * 20); mTickPoints[2].x = Math.round((float) getMeasuredWidth() / 30 * 22); mTickPoints[2].y = Math.round((float) getMeasuredHeight() / 30 * 10); mLeftLineDistance = (float) Math.sqrt(Math.pow(mTickPoints[1].x - mTickPoints[0].x, 2) + Math.pow(mTickPoints[1].y - mTickPoints[0].y, 2)); mRightLineDistance = (float) Math.sqrt(Math.pow(mTickPoints[2].x - mTickPoints[1].x, 2) + Math.pow(mTickPoints[2].y - mTickPoints[1].y, 2)); mTickPaint.setStrokeWidth(mStrokeWidth); } @Override protected void onDraw(Canvas canvas) { drawBorder(canvas); drawCenter(canvas); drawTick(canvas); } private void drawCenter(Canvas canvas) { mPaint.setColor(mUnCheckedColor); float radius = (mCenterPoint.x - mStrokeWidth) * mScaleVal; canvas.drawCircle(mCenterPoint.x, mCenterPoint.y, radius, mPaint); } private void drawBorder(Canvas canvas) { mFloorPaint.setColor(mFloorColor); int radius = mCenterPoint.x; canvas.drawCircle(mCenterPoint.x, mCenterPoint.y, radius * mFloorScale, mFloorPaint); } private void drawTick(Canvas canvas) { if (mTickDrawing && isChecked()) { drawTickPath(canvas); } } private void drawTickPath(Canvas canvas) { mTickPath.reset(); // draw left of the tick if (mDrewDistance < mLeftLineDistance) { float step = (mWidth / 20.0f) < 3 ? 3 : (mWidth / 20.0f); mDrewDistance += step; float stopX = mTickPoints[0].x + (mTickPoints[1].x - mTickPoints[0].x) * mDrewDistance / mLeftLineDistance; float stopY = mTickPoints[0].y + (mTickPoints[1].y - mTickPoints[0].y) * mDrewDistance / mLeftLineDistance; mTickPath.moveTo(mTickPoints[0].x, mTickPoints[0].y); mTickPath.lineTo(stopX, stopY); canvas.drawPath(mTickPath, mTickPaint); if (mDrewDistance > mLeftLineDistance) { mDrewDistance = mLeftLineDistance; } } else { mTickPath.moveTo(mTickPoints[0].x, mTickPoints[0].y); mTickPath.lineTo(mTickPoints[1].x, mTickPoints[1].y); canvas.drawPath(mTickPath, mTickPaint); // draw right of the tick if (mDrewDistance < mLeftLineDistance + mRightLineDistance) { float stopX = mTickPoints[1].x + (mTickPoints[2].x - mTickPoints[1].x) * (mDrewDistance - mLeftLineDistance) / mRightLineDistance; float stopY = mTickPoints[1].y - (mTickPoints[1].y - mTickPoints[2].y) * (mDrewDistance - mLeftLineDistance) / mRightLineDistance; mTickPath.reset(); mTickPath.moveTo(mTickPoints[1].x, mTickPoints[1].y); mTickPath.lineTo(stopX, stopY); canvas.drawPath(mTickPath, mTickPaint); float step = (mWidth / 20) < 3 ? 3 : (mWidth / 20); mDrewDistance += step; } else { mTickPath.reset(); mTickPath.moveTo(mTickPoints[1].x, mTickPoints[1].y); mTickPath.lineTo(mTickPoints[2].x, mTickPoints[2].y); canvas.drawPath(mTickPath, mTickPaint); } } // invalidate if (mDrewDistance < mLeftLineDistance + mRightLineDistance) { postDelayed(new Runnable() { @Override public void run() { postInvalidate(); } }, 10); } } private void startCheckedAnimation() { ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0f); animator.setDuration(mAnimDuration / 3 * 2); animator.setInterpolator(new LinearInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mScaleVal = (float) animation.getAnimatedValue(); mFloorColor = getGradientColor(mUnCheckedColor, mCheckedColor, 1 - mScaleVal); postInvalidate(); } }); animator.start(); ValueAnimator floorAnimator = ValueAnimator.ofFloat(1.0f, 0.8f, 1.0f); floorAnimator.setDuration(mAnimDuration); floorAnimator.setInterpolator(new LinearInterpolator()); floorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mFloorScale = (float) animation.getAnimatedValue(); postInvalidate(); } }); floorAnimator.start(); drawTickDelayed(); } private void startUnCheckedAnimation() { ValueAnimator animator = ValueAnimator.ofFloat(0f, 1.0f); animator.setDuration(mAnimDuration); animator.setInterpolator(new LinearInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mScaleVal = (float) animation.getAnimatedValue(); mFloorColor = getGradientColor(mCheckedColor, mFloorUnCheckedColor, mScaleVal); postInvalidate(); } }); animator.start(); ValueAnimator floorAnimator = ValueAnimator.ofFloat(1.0f, 0.8f, 1.0f); floorAnimator.setDuration(mAnimDuration); floorAnimator.setInterpolator(new LinearInterpolator()); floorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mFloorScale = (float) animation.getAnimatedValue(); postInvalidate(); } }); floorAnimator.start(); } private void drawTickDelayed() { postDelayed(new Runnable() { @Override public void run() { mTickDrawing = true; postInvalidate(); } }, mAnimDuration); } private static int getGradientColor(int startColor, int endColor, float percent) { int startA = Color.alpha(startColor); int startR = Color.red(startColor); int startG = Color.green(startColor); int startB = Color.blue(startColor); int endA = Color.alpha(endColor); int endR = Color.red(endColor); int endG = Color.green(endColor); int endB = Color.blue(endColor); int currentA = (int) (startA * (1 - percent) + endA * percent); int currentR = (int) (startR * (1 - percent) + endR * percent); int currentG = (int) (startG * (1 - percent) + endG * percent); int currentB = (int) (startB * (1 - percent) + endB * percent); return Color.argb(currentA, currentR, currentG, currentB); } public void setOnCheckedChangeListener(OnCheckedChangeListener l) { this.mListener = l; } public interface OnCheckedChangeListener { void onCheckedChanged(SmoothCheckBox checkBox, boolean isChecked); } }
TextSizeUtils(文字大小):
package com.example.zer.text01.util; import android.content.Context; public class TextSizeUtils { /** * 将px值转换为dip或dp值,保证尺寸大小不变 * * @param pxValue (DisplayMetrics类中属性density) * @return */ public static int px2dip(Context context, float pxValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); } /** * 将dip或dp值转换为px值,保证尺寸大小不变 * * @param dipValue (DisplayMetrics类中属性density) * @return */ public static int dip2px(Context context, float dipValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dipValue * scale + 0.5f); } /** * 将px值转换为sp值,保证文字大小不变 * * @param pxValue (DisplayMetrics类中属性scaledDensity) * @return */ public static int px2sp(Context context, float pxValue) { final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (pxValue / fontScale + 0.5f); } /** * 将sp值转换为px值,保证文字大小不变 * * @param spValue (DisplayMetrics类中属性scaledDensity) * @return */ public static int sp2px(Context context, float spValue) { final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (spValue * fontScale + 0.5f); } }
--------------------------------------------------------------------------------------------------------------------
DataBack:
package com.example.zer.text01.presenter; import com.example.zer.text01.model.bean.ResultBean; public interface DataBack { void callbackSuccess(ResultBean resultBean); void callbackFailed(String msg); }
----------------------------------------------------------------------------------------------------------
HttpInterceptor:
package com.example.zer.text01.model.net; import java.io.IOException; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; class HttpInterceptor implements Interceptor { private static final String s = "source"; @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); String url = request.url().toString()+"?source=android"; Request newrequest=request.newBuilder() .url(url) .build(); Response response = chain.proceed(newrequest); return response; } }
-------------------------------------------------------------------------------------------------------
MainMoudle:
package com.example.zer.text01.model.net; import com.example.zer.text01.model.bean.ResultBean; import com.example.zer.text01.presenter.DataBack; import com.google.gson.Gson; import java.io.IOException; import java.util.Map; import okhttp3.Call; import okhttp3.Callback; import okhttp3.Response; public class MainMoudle { //获取手机数据 public void getShopCarData(String url, Map<String,String> parms, final DataBack dataBack){ OkHttpUtil.getInstance().doPost(url, parms, new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { String json = response.body().string(); Gson gson=new Gson(); ResultBean resultBean = gson.fromJson(json, ResultBean.class); dataBack.callbackSuccess(resultBean); } }); } }
-------------------------------------------------------------------------------------------------------
OKhttpUtil:
package com.example.zer.text01.model.net; import java.util.Iterator; import java.util.Map; import java.util.concurrent.TimeUnit; import okhttp3.Callback; import okhttp3.FormBody; import okhttp3.OkHttpClient; import okhttp3.Request; public class OkHttpUtil { static OkHttpUtil okHttpUtil; static OkHttpClient okHttpClient; private OkHttpUtil() { } public static OkHttpUtil getInstance(){ if(okHttpUtil==null){ synchronized (OkHttpUtil.class){ if(okHttpUtil==null){ okHttpUtil=new OkHttpUtil(); okHttpClient=new OkHttpClient.Builder() .readTimeout(5000, TimeUnit.SECONDS) .addInterceptor(new HttpInterceptor()) .connectTimeout(5000,TimeUnit.SECONDS) .build(); } } } return okHttpUtil; } //get请求 public void doGet(String url, Callback callback){ Request request=new Request.Builder() .url(url) .build(); okHttpClient.newCall(request).enqueue(callback); } //post public void doPost(String url, Map<String,String> parms, Callback callback){ FormBody.Builder builder=new FormBody.Builder(); Iterator<String> iterator = parms.keySet().iterator(); while (iterator.hasNext()){ String key = iterator.next(); String value = parms.get(key); builder.add(key,value); } Request request=new Request.Builder() .url(url) .post(builder.build()) .build(); okHttpClient.newCall(request).enqueue(callback); } }
------------------------------------------------------------------------------------------------------
attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="SmoothCheckBox"> <attr name="duration" format="integer"/> <attr name="stroke_width" format="dimension"/> <attr name="color_tick" format="color"/> <attr name="color_checked" format="color"/> <attr name="color_unchecked" format="color"/> <attr name="color_unchecked_stroke" format="color"/> </declare-styleable> </resources>