banner、tablayout、bottomnavigation、viewpager、fragment写安卓界面(可按模块看)

博主自己开发的小项目的界面一,过程中参考了许多其他优秀博主的博文。但时间间隔较长已找不到出处,如有需要请联系博主注明原文出处!谢谢!

先上最终效果图。代码已上传至github,链接见文末。
顶部为轮播图banner空间,放入搜索框(尚未实现具体的搜索功能)。中间为textview组件。“兼职工作”与“短期实习”为tablayout组件,下列表格为recyclerview可拖动。底部为bottomnavigation组件。tablayout组件点击不同标题会呈现不同的列表内容,bottomnavigation尚未实现转换,留待整个项目结束后进行设置(仅有样式)。
图标来源于阿里iconfont
界面一


写在前面

添加的所有依赖如下
module文件

	implementation 'com.youth.banner:banner:1.4.10'
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    //noinspection GradleCompatible
    implementation 'com.android.support:design:28.0.0'
    //noinspection GradleCompatible
    implementation 'com.android.support:recyclerview-v7:28.0.0'
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    implementation 'com.ashokvarma.android:bottom-navigation-bar:2.2.0'

project文件

allprojects {
    repositories {
        google()
        jcenter()
        maven{url 'http://jitpack.io'}
    }
}

设置manifest主题为无主题

android:theme="@style/Theme.AppCompat.Light.NoActionBar">

总注1:最外层布局格式为流式布局
总注2:真机实验型号为HuaweiMate10pro
总注3:代码先后顺序总为先xml后java
总注4:全局变量与部分初始化展示
总注5:具体的命名的颜色不在博客中展示

    private Banner mbanner;
    private SearchView mSearchView;
    private MyImageLoader myImageLoader;
    private ArrayList<Integer> imagePath;
    private ArrayList<String> imageTitle;
    private TextView textView;

    private TabLayout mytab;
    private ViewPager myViewPager;
    private List<String> mtitle = new ArrayList<>();
    private List<Fragment> mFragments = new ArrayList<>();

 private void initData() {
        imagePath = new ArrayList<>();
        imageTitle = new ArrayList<>();
        for (int i=0;i<5;i++){
            imagePath.add(R.mipmap.ic_launcher);//图片(示例图片)
            imageTitle.add("ok"+i);//图片名
        }
    }

banner轮播图与搜索框

   <com.youth.banner.Banner
        android:id="@+id/banner"
        android:layout_width="match_parent"
        android:layout_height="175dp">

        <androidx.appcompat.widget.SearchView
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:layout_marginTop="20dp"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="80dp"
            android:background="@drawable/searchview"
            app:queryHint="软件开发" />

    </com.youth.banner.Banner>

注1:queryHint属性:点击搜索框后默认出现的提示字

 private void initView() {
        myImageLoader = new MyImageLoader();
        mbanner = findViewById(R.id.banner);
        mbanner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR_TITLE);
        //设置圆形指示器和标题
        mbanner.setImageLoader(myImageLoader);
        //设置图片加载器
        mbanner.setBannerAnimation(Transformer.ZoomOutSlide);
        //图片轮播效果(动画常量类)
        mbanner.setBannerTitles(imageTitle);
        //设置图片名(效果图中左下角)
        mbanner.setDelayTime(2000);
        //延迟时间
        mbanner.isAutoPlay(true);
        //是否自动播放
        mbanner.setIndicatorGravity(BannerConfig.CENTER);
        //设置指示器的位置
        mbanner.setImages(imagePath).setOnBannerListener(new OnBannerListener() {
            @Override
            public void OnBannerClick(int position) {
               switch (position){
                   case 0:
                       break;
                   case 1:
                       break;
                   case 2:
                       break;
                   case 3:
                       break;
                   case 4:
                       break;
               }
            }
        }).start();
		//根据图片标号指定动作,示例中没有增加任何动作
    }

public class MyImageLoader extends ImageLoader{

        @Override
        public void displayImage(Context context, Object path, ImageView imageView) {
            Glide.with(context.getApplicationContext()).load(path).into(imageView);
        }
    }

注1:来源于github上的开源项目banner,具体参数可见github上的说明。链接如下:banner的使用及源码
注2:在主方法中调用initView()initData()即可


中间的几个textview(只展示xml)

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/bulletin"
            android:layout_width="100dp"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="快讯"
            android:textSize="30sp" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginLeft="10dp"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:gravity="left|center"
                android:text="大三学生经济独立不是梦"
                android:textSize="15sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:gravity="left|center"
                android:text="互联网企业进入“新寒冬”"
                android:textSize="15sp" />
        </LinearLayout>

    </LinearLayout>

Tablayout与ViewPager

 <com.google.android.material.tabs.TabLayout
            android:id="@+id/MyTab"
            android:layout_width="match_parent"
            android:layout_height="45dp">

 		</com.google.android.material.tabs.TabLayout>
 <androidx.viewpager.widget.ViewPager
            android:id="@+id/MyViewPager"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1">

        </androidx.viewpager.widget.ViewPager>

这是整个界面中比较复杂的部分。因此将全部的代码都贴上来并详细解释。代码中可能会包括之前提到的部分与后面的bottomnavigation部分。
布局文件中有weight=1,是与后面的bottomnavigation组件实现自动填充。即在同一个流式布局中,上下两个固定,中间填满则是weight=1
下面这段代码是MainActivity中的onCreate部分。可以看到在mFragments中添加了自定义的CollectFragment类,这个自定义的类实际上是实现了具体列表内容的recyclerview。把mFragment想象成一个盒子,CollectFragemtn就是自己定义的类型把它装满,而装满后的样子是一个recyclerview列表。

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();//刚才的初始化工作

        mytab = findViewById(R.id.MyTab);
        myViewPager = findViewById(R.id.MyViewPager);//找到对应的组件

        mtitle.add("兼职工作");
        mtitle.add("短期实习");//tablayout中的标题

        mFragments.add(new CollectFragment());
        mFragments.add(new CollectFragment());//在fragment中添加界面

		//为viewPager设置适配器
        myViewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) {
            @NonNull
            @Override
            public Fragment getItem(int position) {
                return mFragments.get(position);
            }

            @Override
            public int getCount() {
                return mFragments.size();//显示多少个界面
            }

            @Override
            public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
                //super.destroyItem(container, position, object);
            }

            @Nullable
            @Override
            public CharSequence getPageTitle(int position) {
                return mtitle.get(position);
            }
        });

        myViewPager.setOffscreenPageLimit(2);//设置预加载界面的数量
        mytab.setupWithViewPager(myViewPager);//设置tablayout界面下的viewpager

    }

先做一些其他准备,定义示例商品的类。不要因为长就放弃!都是可以自动生成的get和set方法以及构造方法。

public class GoodsEntity implements Serializable {
    private String imgPath;
    private String goodsName;
    private String goodsPrice;
    private String goodsRequire;
    private String imgCompany;
    private String Companymes;

    public GoodsEntity(){}

    public String toString(){
        return "GoodsEntity{"+
                "imgPath='"+imgPath+'\''+
                ",goodsName='"+goodsName+'\''+
                ",goodsPrice='"+goodsPrice+'\''+
                '}';
    }

    public String getImgPath() {
        return imgPath;
    }

    public void setImgPath(String imgPath) {
        this.imgPath = imgPath;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    public String getGoodsPrice() {
        return goodsPrice;
    }

    public void setGoodsPrice(String goodsPrice) {
        this.goodsPrice = goodsPrice;
    }

    public String getGoodsRequire() {
        return goodsRequire;
    }

    public void setGoodsRequire(String goodsRequire) {
        this.goodsRequire = goodsRequire;
    }

    public String getImgCompany() {
        return imgCompany;
    }

    public void setImgCompany(String imgCompany) {
        this.imgCompany = imgCompany;
    }

    public String getCompanymes() {
        return Companymes;
    }

    public void setCompanymes(String companymes) {
        Companymes = companymes;
    }

    public GoodsEntity(String imgPath, String goodsName, String goodsPrice, String goodsRequire, String imgCompany, String companymes){
        this.imgPath = imgPath;
        this.goodsName = goodsName;
        this.goodsPrice = goodsPrice;
        this.goodsRequire = goodsRequire;
        this.imgCompany = imgCompany;
        this.Companymes = companymes;
    }

}

接下来是recyclerview的适配器。这其中的R.layout.items是具体内容的布局,可以自己编写xml文件,在此不作展示。

public class CollectRecyclerAdapter extends RecyclerView.Adapter<CollectRecyclerAdapter.myViewHolder> {
    private Context context;
    private ArrayList<GoodsEntity> goodsEntityList;

    //创建构造函数
    public CollectRecyclerAdapter(Context context, ArrayList<GoodsEntity> goodsEntityList) {
        //将传递过来的数据,赋值给本地变量
        this.context = context;//上下文环境
        this.goodsEntityList = goodsEntityList;//实体类数据
    }


    //用于创建ViewHolder实例
    public myViewHolder onCreateViewHolder(ViewGroup parent,int viewType){
        //创建自定义布局   加载布局
        View itemView = View.inflate(context,R.layout.items,null);
        return new myViewHolder(itemView);
    }

    public void onBindViewHolder(myViewHolder holder,int position){
        //根据点击位置绑定数据
        //用于对RecyclerView子项的数据进行赋值,在每个子项被滚动到屏幕内的时候执行
        GoodsEntity data = goodsEntityList.get(position);
        holder.mitemgoodsname.setText(data.getGoodsName());//获取实体类中的name字段并设置
        holder.mitemgodosprice.setText(data.getGoodsPrice());//获取实体类中的price字段并设置
    }

    public int getItemCount(){
        return goodsEntityList.size();
    }

    class myViewHolder extends RecyclerView.ViewHolder{
        private ImageView mitemgoodsimg;
        private TextView mitemgoodsname;
        private TextView mitemgodosprice;

        public myViewHolder(View itemView){
            super(itemView);
            mitemgoodsimg = itemView.findViewById(R.id.item_goods_img);
            mitemgoodsname = itemView.findViewById(R.id.item_goods_name);
            mitemgodosprice = itemView.findViewById(R.id.item_goods_price);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context,"点击了",Toast.LENGTH_SHORT).show();
                    //回传点击监听事件
                    if(onItemClickListener!=null){
                        onItemClickListener.OnItemClick(v,goodsEntityList.get(getLayoutPosition()));
                    }
                }
            });
        }

    }
    /*
     * 设置item的监听事件的接口
     * */
    public interface OnItemClickListener{
        /*
         * @param view 点击的item的试图
         * @param data 点击的item的数据
         * */
        public void OnItemClick(View view, GoodsEntity data);
    }

    //需要外部访问设置set方法方便调用
    private OnItemClickListener onItemClickListener;
    public void setOnItemClickListener(OnItemClickListener onItemClickListener){
        this.onItemClickListener = onItemClickListener;
    }
}

最后一步是实现将前文提到的CollectFragment。这里的xml文件(R.id.collect_recyclerView)布局定义的是具体信息之间的布局格式。

<?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:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/collect_recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>
public class CollectFragment extends Fragment {

    private View view;
    public RecyclerView mCollectRecyclerView;
    private ArrayList<GoodsEntity> goodsEntities = new ArrayList<>();
    private CollectRecyclerAdapter mCollectRecyclerAdapter;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //获取fragment的layout
        view = inflater.inflate(R.layout.collect_page,container, false);
        //对recycleview进行配置
        initRecyclerView();
        //模拟数据
        initData();
        return view;
    }

    private void initData(){
        for(int i=0;i<10;i++){
            GoodsEntity goodsEntity = new GoodsEntity();
            goodsEntity.setGoodsName("软件工程"+i);
            goodsEntity.setGoodsPrice("100"+i*1000);
            goodsEntities.add(goodsEntity);
        }
    }

    private void initRecyclerView() {
        //获取recyclerview
        mCollectRecyclerView=(RecyclerView)view.findViewById(R.id.collect_recyclerView);
        //创建adapter
        mCollectRecyclerAdapter = new CollectRecyclerAdapter(getActivity(), goodsEntities);
        //给recyclerview设置adapter
        mCollectRecyclerView.setAdapter(mCollectRecyclerAdapter);
        //设置layoutmanager,可以设置显示效果是线性布局、grid布局还是瀑布流
        //参数是:上下文、列表方向、是否倒叙
        mCollectRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
        //设置item的分割线
        mCollectRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
        //recyclerview没有item的监听事件,需要自己在适配器中写一个监听事件
        mCollectRecyclerAdapter.setOnItemClickListener(new CollectRecyclerAdapter.OnItemClickListener() {
            @Override
            public void OnItemClick(View view, GoodsEntity data) {
                Toast.makeText(getActivity(),"item", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

至此,中间部分就完成了。总结一下:ViewPager中包含了是最外面的盒子,里面包含了一些碎片fragments,用自定义的CollectFragment进行填充,由适配器决定信息与内容间的格式,xml文件决定内容内部的更具体的文字图片信息格式。


bottomnavigation

在安卓新建项目的时候有自带的bottomnavigation,因此在它的基础上稍微做了一点改动。

<com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/nav_view"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="#fff"
            app:itemTextColor="@color/navigation_item_color"
            app:itemIconTint="@color/navigation_item_color"
            app:labelVisibilityMode="labeled"
            app:menu="@menu/bottom_nav_menu" />

踩过的坑:
1.使用选择器来指定按钮的颜色,根据不同的状态显示不同的颜色。新建一个color文件夹存储各种状态下的不同颜色。代码如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/colorBlack" android:state_checked="false"/>
    <item android:color="@color/colorMyBlue" android:state_checked="true"/>
</selector>

2.menu菜单决定下面的图标个数及格式。注意图标的个数应限制在3-5个。(具体原因及可能出现的问题未知,日后补坑)代码如下:
还要注意的地方是图片格式。如果图片格式是PNG则选择器将起到作用。而图片是SVG则无法改变其颜色(实践结果未看官方文档)

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:enabled="true"
        android:id="@+id/navigation_home"
        android:icon="@mipmap/home"
        app:showAsAction="ifRoom"
        android:title="首页"/>

    <item
        android:enabled="true"
        android:id="@+id/navigation_launch"
        android:icon="@mipmap/add"
        app:showAsAction="ifRoom"
        android:title="发布"/>

    <item
        android:enabled="true"
        android:id="@+id/navigation_message"
        android:icon="@mipmap/message"
        app:showAsAction="ifRoom"
        android:title="消息"/>

    <item
        android:enabled="true"
        android:id="@+id/my"
        android:icon="@mipmap/mine"
        app:showAsAction="ifRoom"
        android:title="我的"/>
</menu>

如果需要对bottomnavigation进行动作监听设置的话可以通过id进行连接。具体设置留坑以后补。
至此页面上的所有组件均已完成。
所有代码上传至github ptjob分支

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章