Android中侧滑菜单效果实现(主界面和菜单界面实现平移、缩放、滚动动画)

编写不易,如有转载,请声明出处: 梦回河口:http://blog.csdn.net/zxc514257857/article/details/72602778

技术要点

  • 自定义侧滑控件SlideMenu
  • 主界面和菜单界面实现伴随移动
  • 根据拖拽的百分比实现平移、缩放、滚动等动画效果
  • ListView的基本使用
  • Butterknife 的使用

Demo展示图片

这里写图片描述

布局代码

//(layout)activity_main
<com.test.slidemenu.view.SlideMenu
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/slideMenu"
    android:background="@mipmap/bg"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--两个子View-->

    <!--引入菜单布局 通过getChildAt(0)获取-->
    <include layout="@layout/layout_menu"/>

    <!--引入主界面布局 通过getChildAt(1)获取-->
    <include layout="@layout/layout_main"/>

</com.test.slidemenu.view.SlideMenu>
-------------------------------------------------------------------
//(layout)layout_main
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:background="#fff"
              android:id="@+id/main_linearlayout"
              android:layout_height="match_parent">

    <FrameLayout
        android:background="#18B4ED"
        android:layout_width="match_parent"
        android:layout_height="60dp">

        <ImageView
            android:layout_marginStart="20dp"
            android:layout_width="50dp"
            android:id="@+id/iv_headMainPic"
            android:layout_gravity="center_vertical"
            android:src="@mipmap/headpic"
            android:layout_height="50dp"/>
    </FrameLayout>

    <ListView
        android:overScrollMode="never"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/main_listview"/>
</LinearLayout>
-------------------------------------------------------------------
//(layout)layout_menu
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/menu_linearlayout"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical" >

    <ImageView android:id="@+id/iv_headMenuPic"
               android:layout_width="90dp"
               android:layout_height="90dp"
               android:background="@mipmap/headpic"
               android:layout_marginTop="50dp"
               android:layout_marginLeft="10dp"/>


    <ListView android:layout_width="match_parent"
              android:layout_marginTop="5dp"
              android:layout_height="match_parent"
              android:id="@+id/menu_listview"/>
</LinearLayout>
-------------------------------------------------------------------
//(layout)mainitem
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="60dp">

        <ImageView
            android:id="@+id/iv_pic"
            android:src="@mipmap/pic"
            android:layout_width="50dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="15dp"/>

        <TextView
            android:id="@+id/tv_contact"
            android:textSize="18sp"
            android:textColor="#FF3E96"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/iv_pic"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </RelativeLayout>
</LinearLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95

自定义侧滑控件代码

//(view)SlideMenu

import android.animation.ArgbEvaluator;
import android.animation.FloatEvaluator;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

/**
 * 自定义SlideMenu控件 实现侧滑效果
 * 为了避免自己去实现onMeasure和onLayout方法 我们继承FrameLayout,系统已经实现好了宽高的测量和位置的摆放
 * 为什么不使用LinearLayout和RelativeLayout,因为FrameLayout代码简洁
 */

public class SlideMenu extends FrameLayout {

    private static final String TAG = "SlideMenu";
    // 通过它来进行View拖拽的实现
    private ViewDragHelper mViewDragHelper;
    private View mMenuView;
    private View mMainView;
    // mainView的拖拽范围
    private int dragRange;
    private int mMainWidth;
    private int mMenuWidth;
    private FloatEvaluator mFloatEvaluator;
    private ArgbEvaluator mArgbEvaluator;
    private OnSlideListener mOnSlideListener;
    // 表示当前状态: 关闭
    private DragState mDragState = DragState.Close;

    public enum DragState{
        Open ,Close
    }

    public SlideMenu(Context context) {
        this(context , null);
    }

    public SlideMenu(Context context, AttributeSet attrs) {
        this(context, attrs , 0);
    }

    public SlideMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initData();
    }

    private void initData(){
        // 父View、滑动敏感度、回调方法
        mViewDragHelper = ViewDragHelper.create(this , callback);
        // 浮点运算器
        mFloatEvaluator = new FloatEvaluator();
        // 颜色运算器
        mArgbEvaluator = new ArgbEvaluator();
    }

    /**
     * 该方法在ViewGroup将子View全部添加进来之后执行,但在onMeasure之前执行
     * 一般用来初始化子View的引用,但是还不能获取到子View的宽高
     */
    @Override
    protected void onFinishInflate() {
        mMenuView = getChildAt(0);
        mMainView = getChildAt(1);
        super.onFinishInflate();
    }

    /**
     * 当onMeasure方法执行完之后执行,在该方法中可以获取所有控件的宽高
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        dragRange = (int) (getMeasuredWidth()*0.6f);
        mMainWidth = mMainView.getMeasuredWidth();
        mMenuWidth = mMenuView.getMeasuredWidth();
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // 让ViewDragHelper帮助我们判断是否应该拦截
        boolean result = mViewDragHelper.shouldInterceptTouchEvent(ev);
        return result;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 让ViewDragHelper帮助我们处理触摸事件
        mViewDragHelper.processTouchEvent(event);
        return true;
    }

    ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
        /**
         * 判断是否需要捕获View的触摸事件
         * 这里的child都是当前触摸的View
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            // 捕获mainView和menuView的触摸事件
            if(child == mMainView || child == mMenuView){
                return true;
            }
            return false;
        }

        /**
         * 当一个View被捕获触摸事件调用
         */
        @Override
        public void onViewCaptured(View capturedChild, int activePointerId) {
            Log.i(TAG , "onViewCaptured:" + activePointerId);
            super.onViewCaptured(capturedChild, activePointerId);
        }

        /**
         * 通过返回值判断滑动方向 只要大于0就可以正常水平垂直滑动
         */
        @Override
        public int getViewHorizontalDragRange(View child) {
            return 1;
        }

        /**
         * 用于捕获子View在水平方向上的移动
         * @param left:是ViewDragHelper帮我们计算好的View最新的left的值
         *            left = child.getLeft() + dx
         * @return 真正想要View的Left变成的值
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            // 限制主界面移动
            if(child == mMainView){
                left = clampLeft(left);
            }
            return left;
        }

//        /**
//         * 用于捕获子View在垂直方向上的移动
//         */
//        @Override
//        public int clampViewPositionVertical(View child, int top, int dy) {
//            return top;
//        }

        /**
         * 当View移动的时候调用,可以获取到手指移动的距离
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            // 当手指在menuView移动的时候,让mainView进行一个伴随的移动,但是menuView不动
            Log.i(TAG , "left: " + left + "dx: " + dx);
            // menuView固定住
            mMenuView.layout(0 ,0 , mMenuWidth , mMenuView.getBottom());

            if(changedView == mMenuView){
                int newLeft = mMainView.getLeft() + dx;
                // 限制newLeft否则,在menuView上滑动mainView无限制
                newLeft = clampLeft(newLeft);
                // 移动mainView
                mMainView.layout(newLeft ,0 , newLeft + mMainWidth , mMainView.getBottom());
            }

            // 增加伴随动画
            float fraction = mMainView.getLeft() * 1.0f / dragRange;
            // 得到百分比
            Log.i(TAG , "fraction" + fraction);
            // 执行动画效果
            execAnim(fraction);
            // 回调监听器的方法
            if(fraction == 0f && mDragState !=DragState.Close){
                mDragState =DragState.Close;
                // 说明关闭了
                if(mOnSlideListener != null){
                    mOnSlideListener.onClose();
                }
                // 说明打开了
            }else if(fraction == 1f && mDragState !=DragState.Open){
                mDragState =DragState.Open;
                if(mOnSlideListener != null){
                    mOnSlideListener.onOpen();
                }
            }

            // 说明在拖拽中
            if(mOnSlideListener != null){
                mOnSlideListener.onDraging(fraction);
            }
            super.onViewPositionChanged(changedView, left, top, dx, dy);
        }

        /**
         * 当手指从View上抬起的时候执行
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            // 判断mainView的left是否是大于dragRange的一半
            if(mMainView.getLeft() > dragRange / 2){
                // mainView平滑滚动到右边
                mViewDragHelper.smoothSlideViewTo(mMainView , dragRange , 0 );
            }else{
                // mainView平滑滚动到左边
                mViewDragHelper.smoothSlideViewTo(mMainView , 0 , 0 );
            }
            // 刷新操作
            ViewCompat.postInvalidateOnAnimation(SlideMenu.this);

            super.onViewReleased(releasedChild, xvel, yvel);
        }
    };

    /**
     * 根据拖拽的百分比来进行伴随动画效果
     */
    private void execAnim(float fraction) {
        // mainView的缩放
        mMainView.setScaleX(mFloatEvaluator.evaluate(fraction , 1.0f , 0.8f));
        mMainView.setScaleY(mFloatEvaluator.evaluate(fraction , 1.0f , 0.8f));

        // menuView的缩放
        mMenuView.setScaleX(mFloatEvaluator.evaluate(fraction , 0.4f , 1f));
        mMenuView.setScaleY(mFloatEvaluator.evaluate(fraction , 0.4f , 1f));

        // menuView 水平方向的平移
        mMenuView.setTranslationX(mFloatEvaluator.evaluate(fraction ,-mMenuWidth /2, 0));

        // 设置SlideMenu的颜色遮罩
        getBackground();
        if(getBackground() != null){
            // 由黑色变为透明的遮罩效果
            int color = (int) mArgbEvaluator.evaluate(fraction, Color.BLACK, Color.TRANSPARENT);
            getBackground().setColorFilter(color, PorterDuff.Mode.DARKEN);
        }
    }

    @Override
    public void computeScroll() {
        // 判断动画有没有结束,如果为true表示没有结束
        if(mViewDragHelper.continueSettling(true)){
            // 刷新操作
            ViewCompat.postInvalidateOnAnimation(SlideMenu.this);
        }
        super.computeScroll();
    }

    /**
     * 修正左边距
     */
    private int clampLeft(int left) {
        if(left > dragRange){
            left = dragRange;
        }else if(left < 0){
            left = 0;
        }
        return left;
    }

    public interface OnSlideListener{
        void onOpen();
        void onClose();
        void onDraging(float fraction);
    }

    public void setOnSlideListener(OnSlideListener mOnSlideListener){
        this.mOnSlideListener = mOnSlideListener;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276

常量类代码

//conf(Constant)
public class Constant {
    public static final String[] SETTINGS = {"激活会员" , "QQ钱包" , "个性装扮" , "我的收藏" , "我的相册" , "我的文件"};
    public static final String[] CONSTACTS = {
            "宋江", "卢俊义","吴用","公孙胜","关胜","林冲","秦明","呼延灼","花荣","柴进","李应","朱仝",
            "鲁智深","武松","董平","张清","扬志","徐宁","索超","戴宗","刘唐","李逵","史进","穆弘",
            "雷横","李俊","阮小二","张横","阮小五","张顺","阮小七","杨雄","石秀","解珍","解宝","燕青",
            "朱武","黄信","孙立","宣赞","赦思文","韩滔","彭玑","单廷","魏定国","萧让","裴宣","欧鹏",
            "邓飞","燕顺","杨林","凌振","蒋敬","吕方","郭盛","安道全","皇浦端","王英","扈三娘","鲍旭",
            "樊瑞","孔明","孔亮","项充","李衮","金大坚","马麟","童威","童猛","孟康","候建","陈达",
            "杨春","郑天寿","陶宗旺","宋清","乐和","龚旺","丁得孙","穆春","曹正","宋万","杜迁","薛永",
            "施恩","李忠","周通","汤隆","杜兴","邹渊","邹润","朱贵","朱富","蔡福","蔡庆","李立",
            "李云","焦挺","石勇","孙新","顾大嫂","张青","孙二娘","王定六","郁保四","白胜","时迁","段景住"
    };
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

activity代码

//(activity)MainActivity
import android.animation.FloatEvaluator;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import com.test.slidemenu.R;
import com.test.slidemenu.view.SlideMenu;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import butterknife.Bind;
import butterknife.ButterKnife;
import static com.test.slidemenu.conf.Constant.CONSTACTS;
import static com.test.slidemenu.conf.Constant.SETTINGS;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private FloatEvaluator mFloatEvaluator;

    @Bind(R.id.iv_headMenuPic)
    ImageView mIvHeadMenuPic;
    @Bind(R.id.menu_listview)
    ListView mMenuListview;
    @Bind(R.id.menu_linearlayout)
    LinearLayout mMenuLinearlayout;
    @Bind(R.id.iv_headMainPic)
    ImageView mIvHeadMainPic;
    @Bind(R.id.main_listview)
    ListView mMainListview;
    @Bind(R.id.main_linearlayout)
    LinearLayout mMainLinearlayout;
    @Bind(R.id.slideMenu)
    SlideMenu mSlideMenu;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
    }

    private void initView() {
        ButterKnife.bind(this);
        mFloatEvaluator = new FloatEvaluator();
    }

    private void initData() {
        mMenuListview.setAdapter(new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, SETTINGS) {
            @NonNull
            @Override
            // 修改布局属性
            public View getView(int position, View convertView, ViewGroup parent) {
                TextView textView = (TextView) super.getView(position, convertView, parent);
                textView.setTextColor(Color.parseColor("#FF3E96"));
                textView.setTextSize(18);
                textView.setSingleLine();
                return textView;
            }
        });
        mMenuListview.setDivider(null);
        mMenuListview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                Toast.makeText(MainActivity.this, SETTINGS[i], Toast.LENGTH_SHORT).show();
            }
        });

        List<Map<String, Object>> data = new ArrayList<>();
        String[] from = {"pic", "contact" };
        int[] to = {R.id.iv_pic, R.id.tv_contact};
        mMainListview.setAdapter(new SimpleAdapter(MainActivity.this, data, R.layout.mainitem, from, to));

        for (int i = 0; i < CONSTACTS.length; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("pic", R.mipmap.pic);
            map.put("contact", CONSTACTS[i]);
            data.add(map);
        }

        mMainListview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                Toast.makeText(MainActivity.this, CONSTACTS[i], Toast.LENGTH_SHORT).show();
            }
        });

        mSlideMenu.setOnSlideListener(new SlideMenu.OnSlideListener() {
            @Override
            public void onOpen() {
                Toast.makeText(MainActivity.this, "onOpen", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onClose() {
                Toast.makeText(MainActivity.this, "onClose", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onDraging(float fraction) {
                Log.i(TAG, "fraction:" + fraction);
                // 沿着y轴旋转
                mIvHeadMainPic.setRotationY(mFloatEvaluator.evaluate(fraction, 0, 720));
            }
        });

        mIvHeadMenuPic.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "我是menuView头像", Toast.LENGTH_SHORT).show();
            }
        });

        mIvHeadMainPic.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "我是mainView头像", Toast.LENGTH_SHORT).show();
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136

  使用Butterknife 需在Module的build.gradle中的dependencies节点下面添加:

compile 'com.jakewharton:butterknife:7.0.1'
  • 1

  目前最新版本为8.6.0。Butterknife配合ButterKnife Zelezny插件使用更佳

  如果对Butterknife和ButterKnife Zelezny插件使用不太清楚可移步:Android中ButterKnife的使用(库和插件)http://blog.csdn.net/zxc514257857/article/details/59195960

Demo下载请移步:http://download.csdn.net/detail/zxc514257857/9848331


———-因本人才疏学浅,如博客或Demo中有错误的地方请大家随意指出,与大家一起讨论,共同进步,谢谢!

猜你喜欢

转载自blog.csdn.net/qq_39539367/article/details/80366383
今日推荐