Android手机应用开发实战(一) | 展示王者荣耀英雄信息的APP

本文介绍了一款Android应用的开发过程,该应用用于展示王者荣耀英雄信息。内容涵盖SmartTabLayout、ToolBar、RecyclerView、HeroSQLiteHelper等组件的使用,详细讲解了英雄的添加、删除、修改和查找功能,以及图片轮换器、收藏功能和分类显示的实现。应用还涉及SQLite数据库操作、多媒体文件选择、音效播放和UI设计等多个方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用说明

系统

  1. 自定义了APP的图标

  2. 启动app查看到启动动画(图片)

    P.S. 可能会出现启动动画消失回到桌面的情况,等待后进入app

  3. 进入app默认显示主界面,底部标签为英雄、装备、铭文、技能

  4. 进入app后播放背景音乐

英雄主界面

  1. 默认显示:搜索框,工具框(ToolBar),添加英雄按钮,收藏英雄显示,英雄分类显示还有具体的英雄列表

  2. 点击搜索框出现候选英雄列表(不输入会默认显示所有英雄列表,输入文字后会匹配输入文本为前缀的英雄名),点击搜索按钮或者候选框中的英雄名称进入英雄详情,如果搜索框中的英雄名不存在会弹出Toast提示

  3. 这是一个图片轮换器,理论上会3秒切换一个英雄(显示英雄海报),且支持循环切换(最后一个英雄切换回最前面一个),在英雄详情页面会有收藏与取消收藏的操作,下面的小圆点会指示当前图片的位置(红色指示)

  4. 添加英雄的按钮,点击之后会跳到添加英雄的页面

  5. 英雄职业的分类显示,点击不同的按钮就会过滤出该职业的英雄,更新英雄列表(搜索框提示列表不受影响)

  6. 英雄列表,网格布局,一共五列,只显示英雄头像,点击会进入英雄详情

1543053765227

1543053897874

英雄详情

  1. 返回主界面按钮
  2. 当前页面名称(英雄)
  3. 更多操作(编辑,删除,保存)
    1. 点击编辑之后,所有可修改的内容都处于可编辑状态(默认是不可编辑状态)
    2. 点击保存之后才能保存内容的修改(包括收藏!收藏之后直接返回是无效的,需要点击保存)
    3. 点击删除按钮之后弹出确认对话框,确定之后删除该英雄并且返回主界面
  4. 英雄头像(可修改)
  5. 英雄名字(不可修改)
  6. 英雄称号(可修改)
  7. 英雄职业(可修改)
  8. 英雄海报(可修改)
  9. 收藏英雄或者取消收藏(只能点击,不能修改)
  10. 英雄生存能力,攻击伤害,技能效果,上手难度数值显示(可修改)
  11. 英雄技能图标按钮,点击查看不同的技能(包括被动只有四个技能,天美最近的英雄技能越来越多了……)(不可修改)
  12. 英雄技能具体描述(不可修改)
  13. 英雄推荐出装(不可修改),点击会跳转到相应的装备详情页面

detail_hero

1543055147962

1543055260034

添加英雄

  1. 返回主界面
  2. 更多操作
    1. 添加头像,弹出系统图片选择框选择图片作为英雄头像(默认是:王者荣耀图标)
    2. 添加语音,弹出系统语音选择框作为英雄语音(默认是:PentaKill语音,享受五杀的感觉!)
  3. 选择英雄海报(默认是:当前图片)
  4. 填写英雄名字(不可为空,不可重复)
  5. 填写英雄称号(默认为:王者小兵)
  6. 填写英雄职业(默认为:法师)
  7. 填写英雄生存能力,攻击伤害,技能效果,上手难度等信息(范围是1-9,默认是1)

1543055421948

1543055629975

导航栏(SmartTabLayout)

使用了GitHub上的这个UI

https://github.com/ogaclejapan/SmartTabLayout

1542817288428

所以activity_main.xml中只有一个ViewPager和一个导航栏,(其实导航栏是在上面)

<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1"
    />
<com.ogaclejapan.smarttablayout.SmartTabLayout
    android:background="@color/colorPrimaryDark"
    android:id="@+id/viewpagertab"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    app:stl_indicatorAlwaysInCenter="false"
    app:stl_indicatorWithoutPadding="false"
    app:stl_indicatorInFront="false"
    app:stl_indicatorInterpolation="smart"
    app:stl_indicatorGravity="bottom"
    app:stl_indicatorColor="#40C4FF"
    app:stl_indicatorThickness="4dp"
    app:stl_indicatorWidth="auto"
    app:stl_indicatorCornerRadius="2dp"
    app:stl_overlineColor="@color/colorPrimary"
    app:stl_overlineThickness="0dp"
    app:stl_underlineColor="#4D000000"
    app:stl_underlineThickness="1dp"
    app:stl_dividerColor="#4D000000"
    app:stl_dividerThickness="1dp"
    app:stl_defaultTabBackground="?attr/selectableItemBackground"
    app:stl_defaultTabTextAllCaps="true"
    app:stl_defaultTabTextColor="@color/white"
    app:stl_defaultTabTextSize="12sp"
    app:stl_defaultTabTextHorizontalPadding="16dp"
    app:stl_defaultTabTextMinWidth="0dp"
    app:stl_distributeEvenly="true"
    app:stl_clickable="true"
    app:stl_titleOffset="24dp"
    app:stl_drawDecorationAfterTab="false"
    />

MainActivity.java

FragmentPagerItemAdapter adapter = new FragmentPagerItemAdapter(
                getSupportFragmentManager(), FragmentPagerItems.with(this)
                .add(R.string.title1, Fragment1.class)
                .add(R.string.title2, Fragment2.class)
                .add(R.string.title3, Fragment3.class)
                .add(R.string.title4, Fragment4.class)
                .create());
        ViewPager viewPager = findViewById(R.id.viewpager);
        viewPager.setAdapter(adapter);
        SmartTabLayout viewPagerTab = findViewById(R.id.viewpagertab);
        viewPagerTab.setViewPager(viewPager);

这里的Fragment1,2,3,4分别是四个页面:英雄,装备,明文,技能

工具栏(ToolBar)

其实有两种ToolBar:

  • android.support.v7.widget.Toolbar
  • Toolbar

两个都能用,但是有一些区别

区别一ToolBar的就是MenuItem显示不出来图标,另一个可以

1542817668675

区别二android.support.v7.widget.Toolbar在设计页面没有预览,另一个有

1542817704898

区别三android.support.v7.widget.Toolbar如果是来自其他Activity跳转过来的,它会自动加上标题,而且会自动有返回按钮,而且添加的菜单栏不太好设计(具体我也忘了),所以除了主界面,其他界面我都是用Toolbar,方便自己定制

使用方法:

fragment1.xml

<android.support.v7.widget.Toolbar
    android:id="@+id/hero_toolbar"
    android:layout_width="match_parent"
    android:layout_height="45dp"
    android:background="@color/colorPrimaryDark">
</android.support.v7.widget.Toolbar>

Android视图下创建一个新的文件夹menu

1542872067478

新建hero_menu.xml

1542872087460

用来保存ToolBar上的菜单栏布局

1542817902374

这里只有一个菜单,表示添加英雄,而且图标用定义的图标

showAsAction表示是否展开到工具栏上

  • always表示总是展开
  • ifRoom表示如果有足够的空间就展开
  • never表示总是不展开
  • withText表示使菜单项和它的图标,菜单文本一起显示。

那么不展开的菜单会到哪里呢?
比如英雄详情页面,它会隐藏在更多按钮里(显示为三个点)

1542818274070

<?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:id="@+id/action_hero_add"
        android:title="添加英雄"
        android:icon="@mipmap/add"
        app:showAsAction="always" />
</menu>

然后需要在Fragment1.java文件中动态设置ToolBar的样式,以及设置点击Item响应的事件,这里只有一个事件,就是跳转到添加英雄页面

//获取ToolBar控件
android.support.v7.widget.Toolbar toolbar = view.findViewById(R.id.hero_toolbar);
toolbar.inflateMenu(R.menu.hero_menu);//设置右上角的填充菜单
toolbar.setOnMenuItemClickListener(new android.support.v7.widget.Toolbar.OnMenuItemClickListener() {
   
    @Override
    public boolean onMenuItemClick(MenuItem menuItem) {
   
        switch (menuItem.getItemId()) {
   
            //添加英雄
            case R.id.action_hero_add:
                Intent intent = new Intent(getActivity(), HeroAdd.class);
                intent.putStringArrayListExtra("hero_names", mAdapter.getAllNames());
                startActivityForResult(intent, 1);
                break;
        }
        return true;
    }
});

还有其他的菜单布局,待会会使用

hero_detail_menu.xml

<?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:id="@+id/action_hero_edit"
        android:title="编辑"
        android:icon="@mipmap/edit"
        app:showAsAction="never" />
    <item
        android:id="@+id/action_hero_save"
        android:title="保存"
        android:icon="@mipmap/save"
        app:showAsAction="never" />
    <item
        android:id="@+id/action_hero_delete"
        android:title="删除"
        android:icon="@mipmap/delete"
        app:showAsAction="never"/>
</menu>

hero_add_menu.xml

<?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:id="@+id/action_hero_add_icon"
        android:title="添加头像"
        app:showAsAction="never"/>
    <item
        android:id="@+id/action_hero_add_voice"
        android:title="添加语音"
        app:showAsAction="never"/>
    <item
        android:id="@+id/action_hero_add_save"
        android:title="保存英雄"
        android:icon="@mipmap/white_save"
        app:showAsAction="ifRoom" />
</menu>

java代码待会再讨论

英雄列表(RecyclerView)

英雄的实体类Hero.java

public class Hero implements Serializable{
   
    //保存的是image的uri
    //英雄海报
    private String image = "android.resource://com.team1.kingofhonor/" +R.mipmap.hero;
    //英雄语音
    private String voice = "android.resource://com.team1.kingofhonor/" +R.raw.pentakill;
    //英雄图标
    private String icon = "android.resource://com.team1.kingofhonor/" +R.mipmap.hero_icon;
    //英雄技能图标
    private String skill1_icon = "android.resource://com.team1.kingofhonor/" +R.mipmap.juyoujing1;
    private String skill2_icon = "android.resource://com.team1.kingofhonor/" +R.mipmap.juyoujing2;
    private String skill3_icon = "android.resource://com.team1.kingofhonor/" +R.mipmap.juyoujing3;
    private String skill4_icon = "android.resource://com.team1.kingofhonor/" +R.mipmap.juyoujing4;
    //英雄技能描述
    private String skill1_description = "技能1";
    private String skill2_description = "技能2";
    private String skill3_description = "技能3";
    private String skill4_description = "技能4";
    //英雄名字
    private String name = "名字未设置";
    //英雄称号
    private String alias = "王者小兵";
    //英雄职业
    private String category;//1.法师 2.刺客 3.射手 4.辅助 5.战士 6.坦克
    //推荐装备
    private String equip1 = "破军";
    private String equip2 = "破军";
    private String equip3 = "破军";
    private String equip4 = "破军";
    private String equip5 = "破军";
    private String equip6 = "破军";
    //生存能力
    private int viability = 1;
    //攻击伤害
    private int attack_damage= 1;
    //技能伤害
    private int skill_damage = 1;
    //上手难度
    private int difficulty = 1;

    private Boolean favorite = false;//收藏
    private Boolean deleted = false;//true表示已经删除
    private Boolean added = false;//true表示是新加的
    private Boolean modified = false;//true表示已经修改

    public Hero(){
   }
    ...
}

这里英雄的语音,头像,海报什么的资源文件全都是存储对应的Uri字符串

列表布局hero_list.xml

其实就显示了一个英雄头像

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="60dp"
android:layout_height="60dp"
    android:layout_margin="5dp"
xmlns:app="http://schemas.android.com/apk/res-auto">

    <ImageView
        android:id="@+id/hero_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitXY"
        android:src="@mipmap/juyoujing_icon"/>


</android.support.constraint.ConstraintLayout>

页面视图fragment1.xml

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/hero_recyclerview"
    tools:listitem="@layout/hero_list"
    android:dividerHeight="10dp"
    android:layout_marginTop="290dp"
    android:layout_marginStart="10dp"
    android:layout_marginEnd="10dp"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent">
</android.support.v7.widget.RecyclerView>

列表适配器HeroAdapter.java

这里仅仅实现了基本的显示功能,后面还会添加新的方法

package com.team1.kingofhonor.adapter;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.team1.kingofhonor.R;
import com.team1.kingofhonor.model.Hero;
import com.team1.kingofhonor.sqlite.HeroSQLiteHelper;

import java.util.ArrayList;
import java.util.List;


public class HeroAdapter extends RecyclerView.Adapter<HeroAdapter.ViewHolder> {
   

    private static List<Hero> mDatas;
    private HeroAdapter.OnItemClickListener onItemClickListener;

    public HeroAdapter(List<Hero> list) {
   
        mDatas = list;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
   
        // 实例化展示的view
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.hero_list, parent, false);
        // 实例化viewholder
        ViewHolder viewHolder = new ViewHolder(v);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
   
        // 绑定数据
        //holder.hero_name.setText(mDatas.get(position).getName());
        holder.hero_image.setImageURI(Uri.parse(mDatas.get(position).getIcon()));
        //listener
        holder.itemView.setOnClickListener(new View.OnClickListener() {
   
            @Override
            public void onClick(final View v) {
   
                if(onItemClickListener != null) {
   
                    int pos = holder.getLayoutPosition();
                    onItemClickListener.onItemClick(holder.itemView, pos);
                }
            }
        });

        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
   
            @Override
            public boolean onLongClick(View v) {
   
                if(onItemClickListener != null) {
   
                    int pos = holder.getLayoutPosition();
                    onItemClickListener.onItemLongClick(holder.itemView, pos);
                }
                //表示此事件已经消费,不会触发单击事件
                return true;
            }
        });

    }

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

    public void addNewItem(Hero f) {
   
        if(mDatas == null) {
   
            mDatas = new ArrayList<>();
        }
        mDatas.add(0, f);
        notifyItemInserted(0);
    }

    public void deleteItem(int pos) {
   
        if(mDatas == null || mDatas.isEmpty()) {
   
            return;
        }
        mDatas.remove(pos);
        notifyItemRemoved(pos);
    }

    public Hero getItem(int pos){
   
        if(mDatas == null || mDatas.isEmpty())
            return null;
        return mDatas.get(pos);
    }
    /**
     * 设置回调监听
     *
     * @param listener
     */
    public void setOnItemClickListener(HeroAdapter.OnItemClickListener listener) {
   
        this.onItemClickListener = listener;
    }

    public interface OnItemClickListener {
   
        void onItemClick(View view, int position);
        void onItemLongClick(View view, int position);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
   
        TextView hero_name;
        ImageView hero_image;
        public ViewHolder(View itemView) {
   
            super(itemView);
            //hero_name = itemView.findViewById(R.id.hero_name);
            hero_image = itemView.findViewById(R.id.hero_image);
        }
    }
}

代码文件Fragment1.java

这里设置成网格显示,一共有5列

private View view;
private RecyclerView.LayoutManager mLayoutManager;
private RecyclerView mRecyclerView;
private HeroAdapter mAdapter;
...
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
   
        view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment1, container, false);
        //hero list
        mLayoutManager = new GridLayoutManager(getActivity(), 5);
        mAdapter = new HeroAdapter(mySQLiteHelper.getAllHeroes());
        mRecyclerView = view.findViewById(R.id.hero_recyclerview);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setAdapter(mAdapter);
        //设置英雄列表的边距
        //mRecyclerView.addItemDecoration(new SpaceItemDecoration(40));
        mAdapter.setOnItemClickListener(new HeroAdapter.OnItemClickListener() {
   
            @Override
            public void onItemClick(View view, int position) {
   
                Intent intent = new Intent(getActivity(), HeroDetail.class);
                Bundle bundle=new Bundle();
                bundle.putSerializable("Click_Hero", mAdapter.getItem(position));
                intent.putExtras(bundle);
                clickPosition = pos
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值