[Android]实现左右滑动界面

__椎名真白 2018-03-29 01:26:02
项目里需要实现一个功能,左右滑动时加载界面,类似于刷题APP,或驾考宝典答题,左右滑动可以查看上一条数据或下一条数据,每个界面控件都是相同的,主要是文本显示的不同而已。网上查找一般都是ViewPager、ViewFlider,多数都是页面数量固定,进行页面切换。我想实现的是能动态加载,即每次左、右滑动,都去本地数据库中去查询相应的数据,然后将信息设置到界面上。
界面设计如下:

左右滑动时界面的效果:

其他的问题都能解决,主要是左右滑动找不到思路,不想一次性加载那么多页面来回切换,不知道那些刷题APP的滑动是如何实现的,设计界面比较乱,大佬们仔细看一下,要怎么实现要求。

...全文
1335 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
__椎名真白 2018-03-30
  • 打赏
  • 举报
回复
这个是活动界面的
package com.my.wordbar.activity;

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.my.wordbar.R;
import com.my.wordbar.bean.DBC2EWordBean;
import com.my.wordbar.bean.DBE2CWordBean;

import org.litepal.crud.DataSupport;

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

public class ReviewActivity extends BaseActivity implements View.OnClickListener {

    private ViewPager viewPager;

    private TextView mTitle;                //标题栏名称

    private LinearLayout mBottomRemember;   //底部操作栏记住了布局按钮
    private LinearLayout mBottomVague;      //底部操作栏模糊布局按钮
    private LinearLayout mBottomUnremember; //底部操作栏没记住布局按钮

    private List<DBE2CWordBean> mEnglishReviewList;  //需要复习的英文单词列表
    private List<DBC2EWordBean> mChineseReviewList;  //需要复习的中文单词列表

    private boolean isHide = false;         //标志位,用于判断当前是屏蔽释义状态还是显示释义状态,默认显示

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_review);

        //初始化控件
        initViews();

        //设置标题栏名称
        mTitle.setText("复习");

        //为底部布局按钮设置点击事件
        mBottomRemember.setOnClickListener(this);
        mBottomVague.setOnClickListener(this);
        mBottomUnremember.setOnClickListener(this);

        //初始化数据列表
        initWords();

    }

    /**
     * 初始化控件
     */
    private void initViews() {

        Toolbar toolbar = (Toolbar) this.findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);       //使用Toolbar

        //改变标题栏的名称。
        mTitle = (TextView) findViewById(R.id.title);

        ActionBar actionBar = getSupportActionBar();    //获取ActionBar实例,具体实现由Toolbar完成
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);  //显示导航按钮设置为true
        }

        mBottomRemember = (LinearLayout) findViewById(R.id.ll_remember);
        mBottomVague = (LinearLayout) findViewById(R.id.ll_vague);
        mBottomUnremember = (LinearLayout) findViewById(R.id.ll_unremember);

        mEnglishReviewList = new ArrayList<>();
        mChineseReviewList = new ArrayList<>();

        viewPager = (ViewPager) findViewById(R.id.vp);

    }

    /**
     * 初始化单词数据,将需要展示的数据查询并装填到List中
     */
    private void initWords() {

        List<Fragment> fragemntList = new ArrayList<>();

        //测试数据 ---> 英文单词,通过查询条件的不同,可以查询到不同的单词信息
        mEnglishReviewList = DataSupport.order("word").find(DBE2CWordBean.class);

        //测试数据 ---> 中文单词,通过查询条件的不同,可以查询到不同的单词信息
//        mChineseReviewList = DataSupport.order("word").find(DBC2EWordBean.class);

        //装填英文单词显示fragment的list
        int englishListSize = mEnglishReviewList.size();
        for (int i = 0;i < englishListSize;i++) {
            Bundle bundle = new Bundle();
            bundle.putString("wordName", mEnglishReviewList.get(i).getWord());
            bundle.putString("wordEnVoiceText", mEnglishReviewList.get(i).getEnVoice());
            bundle.putString("wordAmVoiceText", mEnglishReviewList.get(i).getAmVoice());
            bundle.putString("wordBaseMean", mEnglishReviewList.get(i).getMean());
            bundle.putString("wordExample", mEnglishReviewList.get(i).getExample());
            bundle.putString("wordEnVoiceUrl", mEnglishReviewList.get(i).getEnVoiceUrl());
            bundle.putString("wordAmVoiceUrl", mEnglishReviewList.get(i).getAmVoiceUrl());
            bundle.putInt("currentPage", i + 1);
            Fragment fragment = FragmentView.newInstance(bundle);
            fragemntList.add(fragment);
        }

        //装填中文单词显示fragment的list
        int chineseListSize = mChineseReviewList.size();
        for(int i = 0;i < chineseListSize;i++){
            Bundle bundle = new Bundle();
            bundle.putString("wordName", mChineseReviewList.get(i).getWord());
            bundle.putString("wordCnVoiceText", mChineseReviewList.get(i).getVoice());
            bundle.putString("wordBaseMean", mChineseReviewList.get(i).getMean());
            bundle.putString("wordExample", mChineseReviewList.get(i).getExample());
            bundle.putString("wordCnVoiceUrl", mChineseReviewList.get(i).getVoiceUrl());
            bundle.putInt("currentPage", i + 1);
            Fragment fragment = FragmentView.newInstance(bundle);
            fragemntList.add(fragment);
        }

        //为viewpager设置适配器的数据
        viewPager.setAdapter(new MyFragmentAdapter(getSupportFragmentManager(), fragemntList));
    }

    /**
     * 底部操作栏点击事件
     *
     * @param v LinearLayout控件
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.ll_remember: {
                //设置状态标志位为:记住了,同步更新数据库
                Toast.makeText(this, "操作完成", Toast.LENGTH_SHORT).show();
                break;
            }
            case R.id.ll_vague: {
                //设置状态标志位为:模糊,同步更新数据库
                Toast.makeText(this, "操作完成", Toast.LENGTH_SHORT).show();
                break;
            }
            case R.id.ll_unremember: {
                //设置状态标志位为:没记住,同步更新数据库
                Toast.makeText(this, "操作完成", Toast.LENGTH_SHORT).show();
                break;
            }
        }
    }

    /**
     * 屏蔽基本释义和例句
     */
    private void hideBaseMeanAndExample() {

    }

    /**
     * 展示基本释义和例句
     */
    private void showBaseMeanAndExample() {

    }

    /**
     * 加载toolbar布局
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //加载toolbar布局
        getMenuInflater().inflate(R.menu.review_activity_toolbar, menu);
        return true;
    }

    /**
     * 为按钮设置点击事件
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {

            case R.id.review_bar_hide:
//                Toast.makeText(this, "屏蔽释义\n功能未完成", Toast.LENGTH_SHORT).show();
                TextView action = (TextView) findViewById(R.id.review_bar_hide);
                //将基本释义和例句都屏蔽掉,需要判断当前的状态。
                if (!isHide) {    //默认为false,显示状态,点击后,设置标志为true,标记当前屏蔽状态
                    isHide = true;
                    action.setText("显示释义");
                    hideBaseMeanAndExample();
                } else {          //若当前为屏蔽状态,则设置状态为false,标记当前为显示状态
                    isHide = false;
                    action.setText("屏蔽释义");
                    showBaseMeanAndExample();
                }
                break;

            case android.R.id.home:
                //前往主界面
                Intent intent = new Intent(ReviewActivity.this, MainActivity.class);
                startActivity(intent);
                finish();
                break;

            default:
        }
        return true;
    }

    /**
     * 自定义的fragment的适配器
     * 创建适配器只需要getSupportFragmentManager()和设置好的fragment的list
     */
    private class MyFragmentAdapter extends FragmentStatePagerAdapter {

        List<Fragment> list;

        MyFragmentAdapter(FragmentManager fm, List<Fragment> fragemntList) {
            super(fm);
            this.list = fragemntList;
        }

        /**
         * 返回需要展示的fragment
         *
         * @param position 展示的fragment的位置
         * @return 该位置的fragment
         */
        @Override
        public Fragment getItem(int position) {
            return list.get(position);
        }

        /**
         * 返回需要展示的fangment数量
         *
         * @return list中fragment的数量
         */
        @Override
        public int getCount() {
            return list.size();
        }
    }
}
其他功能就通过fragment和Activity之间的通信就可以解决了。简单优化一下,这个模块就不管了。。。
__椎名真白 2018-03-30
  • 打赏
  • 举报
回复
效果出来了,使用的是fagment + viewpager 实现的效果。

不得不说到AppCompatActivity的强大,v4包下嵌入fragment需要活动继承FragmentActivity,获取fragment管理对象getSupportFragmentManager(),它能兼容到1.6,而app包下的fragment则是兼容到3.0,虽然不用fragment依赖的活动继承FragmentActivity,直接继承Activity就可以。但是如果想兼容更低的版本,就需要使用v4包,还要继承FragmentActivity,如果想要使用系统状态栏、Toolbar是不可以的,AppCompatActivity的出现就完全避免了FragmentActivity的弊端,可以继续使用状态栏和自定义的toolbar。真的厉害。
效果有了,再继续加一点动画效果,优化一下布局,就完全OK了。
代码比较长,就贴fragment的实现还有依赖的活动实现好了:
package com.my.wordbar.activity;

import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.my.wordbar.R;
import com.my.wordbar.util.JinshanParseUtil;

public class FragmentView extends Fragment {

private Bundle mWordMessage; //存储传递过来的单词信息

private TextView mTitle; //标题栏名称

private TextView mWordName; //单词名称
private TextView mWordBaseMeanLab; //基本释义Lab
private TextView mWordBaseMean; //单词基本释义
private TextView mWordExampleLab; //相关例句Lab
private TextView mWordExample; //单词相关例句

private TextView mEnVoiceLab; //英式发音Lab
private TextView mAmVoiceLab; //美式发音Lab
private TextView mEnVoiceText; //英式发音文本
private TextView mAmVoiceText; //美式发音文本

private String mEnVoiceUrl; //记录英式发音网址
private String mAmVoiceUrl; //记录美式发音网址
private String mCnVoiceUrl; //记录中文发音网址

private ImageView mEnVoiceImg; //英式发音小喇叭
private ImageView mAmVoiceImg; //美式发音小喇叭

private LinearLayout mAmVoiceRoot; //整个美式发音布局

private int mCurrentPage; //当前的页面从 1 开始

/**
* 创建时调用,获取Activity为fragment设置好的数据
* @param savedInstanceState 同Activity的Bundle参数
*/
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mWordMessage = getArguments();
}

/**
* 创建视图
* @param inflater 布局加载器
* @param container 创建好的视图要加入到ViewGroup中
* @param savedInstanceState 保存信息
* @return 创建好的视图
*/
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

//加载fragment的布局
View view = inflater.inflate(R.layout.review_fragment,null);

//初始化fragment中的控件
initViews(view);

//利用Activity传递过来的数据初始化单词的显示信息
initWordMessage();

//返回创建好的view视图
return view;
}

/**
* 初始化控件
* @param view fragment布局对应的view
*/
private void initViews(View view){
mTitle = (TextView) view.findViewById(R.id.title); //标题栏名称

mWordName = (TextView) view.findViewById(R.id.tv_word_name); //单词名称
mWordBaseMeanLab = (TextView) view.findViewById(R.id.tv_base_mean_lab); //基本释义Lab
mWordBaseMean = (TextView) view.findViewById(R.id.tv_base_mean); //单词基本释义
mWordExampleLab = (TextView) view.findViewById(R.id.tv_word_examples_lab); //相关例句Lab
mWordExample = (TextView) view.findViewById(R.id.tv_word_examples); //单词相关例句
mEnVoiceLab = (TextView) view.findViewById(R.id.en_voice_lab); //英式发音Lab
mEnVoiceText = (TextView) view.findViewById(R.id.en_voice_text); //英式发音文本
mAmVoiceText = (TextView) view.findViewById(R.id.am_voice_text); //美式发音文本

mEnVoiceImg = (ImageView) view.findViewById(R.id.iv_en_voice); //英式发音小喇叭
mAmVoiceImg = (ImageView) view.findViewById(R.id.iv_am_voice); //美式发音小喇叭

mAmVoiceRoot = (LinearLayout) view.findViewById(R.id.ll_am_voice_root); //整个美式发音布局
}

/**
* 初始化需要展示的单词信息,从传入的Bundle中取出并设置到控件上
*/
private void initWordMessage() {

mCurrentPage = mWordMessage.getInt("currentPage");

if (JinshanParseUtil.isEnglish(mWordMessage.getString("wordName"))){
//设置英式、美式发音布局显示,有可能上一个中文单词,导致该布局被隐藏
mEnVoiceLab.setText("英式发音:"); //恢复英式发音Lab文本
mAmVoiceRoot.setVisibility(View.VISIBLE); //重新显示美式发音布局

//为所有文本控件设置显示文本
mWordName.setText(mWordMessage.getString("wordName"));
mEnVoiceText.setText(mWordMessage.getString("wordEnVoiceText"));
mAmVoiceText.setText(mWordMessage.getString("wordAmVoiceText"));
mWordBaseMean.setText(mWordMessage.getString("wordBaseMean"));
mWordExample.setText(mWordMessage.getString("wordExample"));

//获得英式、美式发音的网址
mEnVoiceUrl = mWordMessage.getString("wordEnVoiceUrl");
mAmVoiceUrl = mWordMessage.getString("wordAmVoiceUrl");

//英式发音小喇叭点击事件
mEnVoiceImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playVoice(mEnVoiceUrl);
}
});

//美式发音小喇叭点击事件
mAmVoiceImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playVoice(mAmVoiceUrl);
}
});
}else{
//中文没有英式和美式发音,所以要对界面进行调整
mEnVoiceLab.setText("拼音发音:"); //复用英式发音Lab控件
mAmVoiceRoot.setVisibility(View.GONE); //隐藏美式发音布局

//为所有文本控件设置显示文本
mWordName.setText(mWordMessage.getString("wordName"));
mEnVoiceText.setText(mWordMessage.getString("wordCnVoiceText")); //复用英式发音文本控件
mWordBaseMean.setText(mWordMessage.getString("wordBaseMean"));
mWordExample.setText(mWordMessage.getString("wordExample"));

//获得拼音发音的网址
mCnVoiceUrl = mWordMessage.getString("wordCnVoiceUrl");

//发音小喇叭的点击事件,复用英式发音小喇叭控件
mEnVoiceImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playVoice(mCnVoiceUrl);
}
});
}
}

/**
* 开启线程,准备播放声音
* @param voiceUrl 声音网址
*/
private void playVoice(final String voiceUrl){

//因为会有声音为空的情况,如用户自行添加的单词,没有添加录音,则声音网址为:"空"
if (voiceUrl.equals("空")){
Toast.makeText(getActivity(), "抱歉,该词没有发音信息!", Toast.LENGTH_SHORT).show();
}else{ //开启线程,准备播放
new Thread(new Runnable() {
@Override
public void run() {
startPlayVoice(voiceUrl);
}
}).start();
}
}

/**
* 开始播放声音,使用MediaPlayer
* @param voiceUrl 声音网址
*/
private void startPlayVoice(String voiceUrl){
try {
final MediaPlayer mediaPlayer;
//装填发音网址
mediaPlayer = MediaPlayer.create(getActivity(), Uri.parse(voiceUrl));
mediaPlayer.start();
//回调方法,若播放完毕,则释放资源
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mediaPlayer.release();
}
});
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getActivity(), "播放失败!", Toast.LENGTH_SHORT).show();
}
}

/**
* 创建fragment实例,并将Activity设置的数据传入
* @param args Activity中设置好的数据,都存储在Bundle中
* @return 返回创建好的fragment
*/
public static FragmentView newInstance(Bundle args) {
FragmentView fragment = new FragmentView();
fragment.setArguments(args);
return fragment;
}
}

__椎名真白 2018-03-29
  • 打赏
  • 举报
回复
刚把界面写完,我试试大佬们提供的方法
新问题:这个ScrollView的上拉和下拉时出现的一片橘色区域该怎么去掉。。。
阿道夫小狮子 2018-03-29
  • 打赏
  • 举报
回复
用fragment+viewpager
weixin_38437506 2018-03-29
  • 打赏
  • 举报
回复
谢谢分享......
键盘舞者113 2018-03-29
  • 打赏
  • 举报
回复
说白了你想要Fragment进行懒加载,你创建的时候不加载,你翻到的时候加载界面,地下源码可以自己试一下
https://www.jianshu.com/p/8a772b9df6d5

80,350

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧