Android MaterialDesign控件使用以及RecyclerView,ItemDecoration的基本使用

在谷歌给我们提供的appcompat包中有很多为兼容而生的控件,这样就可以做到高低版本和不同的ROM之间体验一致!还可以配合appcompat的主题使用达到体验一致性。

appcompat控件以及样式

  • 文本 AppCompatTextView
  • 按钮 AppCompatButton
  • 提示框 android.support.v7.app.AlertDialog`
  • 文本输入框 AppCompatEditText
  • 下拉刷新 SwipeRefreshLayout
  • 进度条样式 style=”@style/Widget.AppCompat.ProgressBar.Horizontal”
  • 列表Popup框 ListPopupWindow
  • 菜单Popup框 PopupMenu
  • 列表间隔线 LinearLayoutCompat
  • RecyclerView android.support.v7.widget.RecyclerView

接下来让我们来看一下这些控件的一些基本使用方法。

AppCompatTextView

        <android.support.v7.widget.AppCompatTextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="5dp"
            android:text="Hello World" />

AppCompatButton

        <android.support.v7.widget.AppCompatButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="5dp"
            android:onClick="showDialog"
            android:text="对话框" />

ProgressBarStyle

        <ProgressBar
            style="@style/Widget.AppCompat.ProgressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="16dp" />

AppCompatEditText

        <android.support.v7.widget.AppCompatEditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="5dp"
            android:text="呵呵" />

显示效果如图:
这里写图片描述


可以看到整个界面都是MD的一个风格

android.support.v7.app.AlertDialog

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("XY的提示框");
builder.setMessage("给XY一个女朋友");
builder.setPositiveButton("好的", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {

    }
});
builder.setNegativeButton("不行", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {

    }
});
builder.show();

这里写图片描述

ListPopupwindow

    public void showListPopupwindow(View view){
        String[] datas = {"条目0","条目1","条目2","条目3","条目4"};
        ListAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,datas);
        ListPopupWindow listPopupWindow = new ListPopupWindow(this);
        listPopupWindow.setAdapter(adapter);
        listPopupWindow.setAnchorView(view);
        listPopupWindow.show();
    }

这里写图片描述

PopupMenu

public void showPopupmenuwindow(View view){
    PopupMenu popupMenu = new PopupMenu(this,view);
    popupMenu.getMenuInflater().inflate(R.menu.main,popupMenu.getMenu());
    popupMenu.show();
}
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:icon="@android:drawable/ic_menu_set_as"
        android:title="设置"/>
    <item
        android:id="@+id/action_share"
        android:orderInCategory="101"
        android:icon="@android:drawable/ic_menu_share"
        android:title="分享"/>
    <item
        android:id="@+id/action_new"
        android:orderInCategory="102"
        android:icon="@android:drawable/ic_menu_add"
        android:title="添加"/>

</menu>

这里写图片描述


LinearLayoutCompat

    <android.support.v7.widget.LinearLayoutCompat
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:divider="@drawable/abc_list_divider_mtrl_alpha"
        app:showDividers="beginning|middle">

        <android.support.v7.widget.AppCompatTextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="5dp"
            android:text="Hello World" />

        <android.support.v7.widget.AppCompatButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="5dp"
            android:onClick="showDialog"
            android:text="对话框" />

        <ProgressBar
            style="@style/Widget.AppCompat.ProgressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="16dp" />

        <android.support.v7.widget.AppCompatButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="5dp"
            android:onClick="showListPopupwindow"
            android:text="显示ListPopupwindow" />


        <android.support.v7.widget.AppCompatButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="5dp"
            android:onClick="showPopupmenuwindow"
            android:text="显示showPopupmenuwindow" />

        <android.support.v7.widget.AppCompatEditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="5dp"
            android:text="呵呵" />

        <android.support.v7.widget.AppCompatButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:onClick="toRecyclerView"
            android:layout_marginBottom="5dp"
            android:text="RecyclerView" />

        <android.support.v7.widget.AppCompatButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            android:layout_marginTop="16dp"
            android:onClick="toHeaderRecyclerView"
            android:layout_marginBottom="5dp"
            android:text="带headerView以及footerView的RecyclerView" />
    </android.support.v7.widget.LinearLayoutCompat>

这里写图片描述

可以看到每一个childView之间都有一根间隔线
app:showDividers=”beginning|middle”的意思就是第一个子view上有间隔线以及每一个子view之间也有间隔线


下面要说到最重要的一个控件RecyclerView了,可以说是ListView和GridView的增强升级版,但是RecyclerView比这两个哥们要牛逼的多,话不多说,直接上代码

public class RecyclerViewActivity extends AppCompatActivity{

    private Handler handler = new Handler();
    private RecyclerView rv;
    private List<String> items;
    private XYAdapter xyAdapter;
    private RecyclerView.ItemDecoration dividerItemDecoration;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recyclerview);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        items = new ArrayList<>();
        for (int i = 0; i < 90; i++) {
            items.add("条目" + i);
        }
        rv = (RecyclerView) findViewById(R.id.recyclerview);
        xyAdapter = new XYAdapter(items);
        xyAdapter.setOnItemClickListener(new XYBaseAdapter.OnItemClickListener() {
            @Override
            public void OnItemClick(View v, int position) {
                Toast.makeText(RecyclerViewActivity.this, "点击" + position, Toast.LENGTH_SHORT).show();
            }
        });
        rv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        rv.setAdapter(xyAdapter);
        rv.setItemAnimator(new DefaultItemAnimator());
        /**
         * 添加条目间隔线
         */
        dividerItemDecoration =  new DividerItemDecoration(this,LinearLayoutManager.VERTICAL);
        rv.addItemDecoration(dividerItemDecoration);

        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new XYItemTouchHelperCallBack(xyAdapter));
        itemTouchHelper.attachToRecyclerView(rv);
    }

    /**
     * 添加一个item
     * @param view
     */
    public void addItem(View view){
        xyAdapter.addData("add item",3);
    }

    /**
     * 删除一个item
     * @param view
     */
    public void removeItem(View view){
        xyAdapter.removeData(3);
    }
}

重点在这两行代码:

rv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
rv.setAdapter(xyAdapter);

recyclerView设置LayoutManager来管理布局,设置Adapter来绑定数据,来看一下Adapter如何实现

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class XYBaseAdapter<T> extends RecyclerView.Adapter<XYBaseAdapter<T>.XYViewHolder> {

    protected List<T> mItems;

    private OnItemClickListener mOnItemClickListener;

    public XYBaseAdapter(List<T> items) {
        mItems = items;
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        mOnItemClickListener = listener;
    }

    @Override
    public XYViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View root = LayoutInflater.from(parent.getContext()).inflate(getContentLayoutId(), parent, false);
        XYViewHolder viewHolder = new XYViewHolder(root);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(XYViewHolder holder, int position) {
        ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
        lp.height = 100;
        holder.itemView.setOnClickListener(new XYOnItemClickListener(holder.getLayoutPosition()));
        bindData(holder, position);
    }

    protected abstract int getContentLayoutId();

    protected abstract void bindData(XYViewHolder holder, int position);


    @Override
    public int getItemCount() {
        return mItems.size();
    }


    /**
     * 刷新数据
     * @param datas
     */
    public void refresh(List<T> datas){
        this.mItems.clear();
        this.mItems.addAll(datas);
        notifyDataSetChanged();
    }

    /**
     * 添加数据
     * @param datas
     */
    public void addData(List<T> datas){
        this.mItems.addAll(datas);
        notifyDataSetChanged();
    }

    public void addData(T t,int position){
        this.mItems.add(position,t);
        notifyItemInserted(position);
    }

    public void removeData(int position){
        this.mItems.remove(position);
        notifyItemRemoved(position);
    }

    public void removeData(){
        this.mItems.clear();
        notifyDataSetChanged();
    }

    class XYViewHolder extends RecyclerView.ViewHolder {

        private Map<Integer, View> mCache = new HashMap<>();

        public XYViewHolder(View itemView) {
            super(itemView);
        }

        public View findView(int res) {
            if (mCache.get(res) == null) {
                mCache.put(res, itemView.findViewById(res));
            }
            return mCache.get(res);
        }
    }

    public interface OnItemClickListener {
        void OnItemClick(View v, int position);
    }


    public class XYOnItemClickListener implements View.OnClickListener {

        int mPosition;

        public XYOnItemClickListener(int position) {
            mPosition = position;
        }

        @Override
        public void onClick(View v) {
            if (mOnItemClickListener != null)
                mOnItemClickListener.OnItemClick(v, mPosition);
        }
    }
}

方法onCreateViewHolder中创建返回ViewHolder,在onBindViewHolder方法中绑定相关数据,此处抽象优化出来让子类继承实现bindData方法,getContentLayoutId方法实现类返回item的局部id,看一下XYBaseAdapter的实现类

public class XYAdapter extends XYBaseAdapter<String> implements XYMoveListener {

    public XYAdapter(List<String> items) {
        super(items);
    }

    @Override
    protected int getContentLayoutId() {
        return R.layout.recyclerview_item;
    }

    @Override
    protected void bindData(XYViewHolder holder, int position) {
        TextView tv = (TextView) holder.findView(R.id.content);
        tv.setText(mItems.get(position) + "");
    }
}

看一下效果
这里写图片描述

图中每一个item之间都有一条间隔线,这个要怎么做到呢?我们需要用到ItemDecoration类了,代码撸起来

public class DividerItemDecoration extends RecyclerView.ItemDecoration {

    private int[] attrs = new int[]{android.R.attr.listDivider};
    private Drawable dividerDrawable;
    private int mOrientation;

    public DividerItemDecoration(Context context, int orientation) {
        TypedArray ta = context.obtainStyledAttributes(attrs);
        dividerDrawable = ta.getDrawable(0);
        ta.recycle();
        setOrientation(orientation);
    }

    private void setOrientation(int orientation) {
        if (orientation != LinearLayoutManager.HORIZONTAL && orientation != LinearLayoutManager.VERTICAL) {
            throw new IllegalArgumentException("布局参数错误");
        }
        this.mOrientation = orientation;
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == LinearLayoutManager.HORIZONTAL) {
            drawVerticalDivider(c, parent);
        } else if (mOrientation == LinearLayoutManager.VERTICAL) {
            drawHorizontalDivider(c, parent);
        }
    }

    private void drawVerticalDivider(Canvas c, RecyclerView parent) {
        int top = parent.getPaddingTop();
        for (int i = 0; i < parent.getChildCount(); i++) {
            View childView = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) childView.getLayoutParams();
            int bottom = childView.getBottom() + params.bottomMargin;
            int left = childView.getRight() + params.rightMargin;
            int right = left + dividerDrawable.getIntrinsicWidth();
            dividerDrawable.setBounds(left, top, right, bottom);
            dividerDrawable.draw(c);
        }
    }

    private void drawHorizontalDivider(Canvas c, RecyclerView parent) {
        int left = parent.getLeft() + parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();
        for (int i = 0; i < parent.getChildCount(); i++) {
            View childView = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) childView.getLayoutParams();
            int top = childView.getBottom() + params.topMargin + Math.round(ViewCompat.getTranslationY(childView));
            int bottom = top + dividerDrawable.getIntrinsicHeight();
            dividerDrawable.setBounds(left, top, right, bottom);
            dividerDrawable.draw(c);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == LinearLayoutManager.HORIZONTAL) {
            outRect.set(0, 0, dividerDrawable.getIntrinsicWidth(), 0);
        } else if (mOrientation == LinearLayoutManager.VERTICAL) {
            outRect.set(0, 0, 0, dividerDrawable.getIntrinsicHeight());
        }
    }
}
  • 首先我们来看getItemOffsets方法,这个方法的意思就是需要我们返回一个Rect的偏移区域来展现divider,outRect.set(left,top,right,bottom);设置左上右下的偏移区域;

  • 再来看onDraw方法,这个方法就是具体实现divider分隔线的地方了,循环遍历所有子view,通过计算left,top,right,bottom来确定每一条分隔线的位置。


如果我们需要添加条目,需要在数据集合中添加一条数据,并且调用方法notifyItemInserted(position);
如果我们需要删除一个条目,需要在数据集合中删除一条数据,并且调用方法notifyItemRemoved(position);
添加删除条目时如需要一些动画效果可以在recyclerview中添加Animator,这里我们添加一个默认的Animator,rv.setItemAnimator(new DefaultItemAnimator());

这里写图片描述

下面我们再来看一下布局变换如何实现

    public boolean onOptionsItemSelected(MenuItem item) {
        rv.removeItemDecoration(dividerItemDecoration);
        switch (item.getItemId()) {
            case R.id.action_LinearLayoutManager_HORIZATOAL:
                xyAdapter.setStaggerLayout(false);
                dividerItemDecoration =  new DividerItemDecoration(this,LinearLayoutManager.HORIZONTAL);
                rv.addItemDecoration(dividerItemDecoration);
                rv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
                break;
            case R.id.action_LinearLayoutManager_VERTICAL:
                xyAdapter.setStaggerLayout(false);
                dividerItemDecoration =  new DividerItemDecoration(this,LinearLayoutManager.VERTICAL);
                rv.addItemDecoration(dividerItemDecoration);
                rv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
                break;
            case R.id.action_GridLayoutManager:
                xyAdapter.setStaggerLayout(false);
                dividerItemDecoration =  new GridItemDecoration(this);
                rv.addItemDecoration(dividerItemDecoration);
                rv.setLayoutManager(new GridLayoutManager(this, 3));
                break;
            case R.id.action_StaagerLayoutManager:
                xyAdapter.setStaggerLayout(true);
                rv.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL));
                break;
        }

        return super.onOptionsItemSelected(item);
    }

效果图:
这里写图片描述


最后奉上源码地址:
XYMaterialDesign

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值