加上广告之后百度就不让上了,客服说让我在线配置隐藏广告在上架,我可不是那种藏着掖着的人,哈哈,所以只能在云盘下载了
- 下载地址:
https://yunpan.cn/cqt5xp3QAJsSM (提取码:ffaa)
第一大步肯定是需求分析,那么
·这个背单词的软件需要具备的功能:
- 查词
- 每日一句
- 卡片单词,单词本,等级测试,美文欣赏(具体形式后面实现时候再介绍)
- 设置(包括:个人设置,词库下载,缓存清理等)
大概就分这四个模块,所以样式就定成很大众的四个tab页实现
·数据来源及方式,数据库设计,
1.我选择了ICIBA 金山词霸API,因为相对有道等其他api接口,金山提供了单词,词音,每日一句及发音等 很全面.非常符合我们的需求.
2.数据库方面,主要就是记录查询过的单词,和单词测试里学习过的单词,字段都很相似
- 单词,英音标,美音标,英发音,美发音,释义,例句,查询次数,和答错次数.
根据需求删减某系字段即可.
今天主要说明一下ViewPger+Fragment实现主界面Tab的切换效果,先看效果:
基本原理就是ViewPager里面放了四个Fragment,就是这么简单,稍微复杂点就是底下图标的渐变效果.
首先如何在ViewPager里面放了四个Fragment
- xml里声明这个控件等价于一个TextView;
- 出镜成员:ViewPager Fragment List FragmentPagerAdapter
private ViewPager mViewPager; // 主界面fragment容器
private List<Fragment> mTabs = new ArrayList<Fragment>(); // fragment集合
private FragmentPagerAdapter mAdapter; // 适配器
private List<TabIcon> mTabIndicators = new ArrayList<TabIcon>(); // 渐变图标集合
- 将Fragment放入List中,
//添加四个tab的fragment
mTabs = new ArrayList<Fragment>();
自己建的Fragment fragment1 = new 自己建的Fragment();
mTabs.add(fragment1);
自己建的Fragment fragment2 = new 自己建的Fragment();
mTabs.add(fragment2);
自己建的Fragment fragment3 = new 自己建的Fragment();
mTabs.add(fragment3);
自己建的Fragment fragment4 = new 自己建的Fragment();
mTabs.add(fragment4);
- 将List放入FragmentPagerAdapter,
mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Fragment getItem(int arg0) {
return mTabs.get(arg0);
}
};
- 最后将FragmentPagerAdapter绑定在ViewPager上 ,
mViewPager.setAdapter(mAdapter);
mViewPager.setOffscreenPageLimit(10);//这句话的意思就是再每一个fragment左右各保存5个fragment页面,此参数默认为2,为2时当你滑动到第三个fragment的时候第一个已经被销毁当你滑动回来需要重新加载,数据就没了,所以设置为10,也就是当滑动到第四个依然能保存第一个.
主界面代码:
public class MainActivity extends FragmentActivity
implements OnClickListener, OnPageChangeListener, IAtSettingFragment {
private ViewPager mViewPager; // 主界面fragment容器
private List<Fragment> mTabs = new ArrayList<Fragment>(); // fragment集合
private FragmentPagerAdapter mAdapter; // 适配器
private List<TabIcon> mTabIndicators = new ArrayList<TabIcon>(); // 渐变图标集合
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initDatas();
mViewPager.setAdapter(mAdapter);
mViewPager.setOffscreenPageLimit(10);
initEvent();
}
/**
* 初始化事件和服务
*/
@SuppressWarnings("deprecation")
private void initEvent() {
mViewPager.setOnPageChangeListener(this);
Intent intent = new Intent(this, NotifyReviewService.class);
startService(intent);
}
InterpretFragment interpretFragment;
DailyFragment tabFragment;
ReciteFragment reciteFragment;
MeFragment meFragment;
/**
* 初始化数据(界面 词库)
*/
private void initDatas() {
// 导入词库
new WriteToSD(this);
//添加四个tab的fragment
interpretFragment = new InterpretFragment();
mTabs.add(interpretFragment);
tabFragment = new DailyFragment();
mTabs.add(tabFragment);
reciteFragment = new ReciteFragment();
mTabs.add(reciteFragment);
meFragment = new MeFragment();
mTabs.add(meFragment);
mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Fragment getItem(int arg0) {
return mTabs.get(arg0);
}
};
}
/**
* 找控件和绑定监听器
*/
private void initView() {
mViewPager = (ViewPager) findViewById(R.id.viewPager);
TabIcon one = (TabIcon) findViewById(R.id.tab_one);
mTabIndicators.add(one);
TabIcon two = (TabIcon) findViewById(R.id.tab_two);
mTabIndicators.add(two);
TabIcon three = (TabIcon) findViewById(R.id.tab_three);
mTabIndicators.add(three);
TabIcon four = (TabIcon) findViewById(R.id.tab_four);
mTabIndicators.add(four);
one.setOnClickListener(this);
two.setOnClickListener(this);
three.setOnClickListener(this);
four.setOnClickListener(this);
one.setIconAlpha(1.0f);//初始化图标透明度
}
@Override
public void onClick(View v) {
resetOtherTabs();
switch (v.getId()) {
case R.id.tab_one:
mTabIndicators.get(0).setIconAlpha(1.0f);
mViewPager.setCurrentItem(0, false);
break;
case R.id.tab_two:
mTabIndicators.get(1).setIconAlpha(1.0f);
mViewPager.setCurrentItem(1, false);
break;
case R.id.tab_three:
mTabIndicators.get(2).setIconAlpha(1.0f);
mViewPager.setCurrentItem(2, false);
break;
case R.id.tab_four:
mTabIndicators.get(3).setIconAlpha(1.0f);
mViewPager.setCurrentItem(3, false);
break;
}
}
/**
* 重制其他Tab的颜色
*/
private void resetOtherTabs() {
for (int i = 0; i < mTabIndicators.size(); i++) {
mTabIndicators.get(i).setIconAlpha(0);
}
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
if (arg1 > 0) {
TabIcon left = mTabIndicators.get(arg0);
TabIcon right = mTabIndicators.get(arg0 + 1);
left.setIconAlpha(1 - arg1);
right.setIconAlpha(arg1);
}
}
@Override
public void onPageSelected(int arg0) {
switch (arg0) {
case 1:
interpretFragment.setSearchedPosition();
break;
case 3:
meFragment.setTvCardCount();
break;
}
}
// 实现查询单词数的更新
@Override
public void onQuery(String szContent) {
meFragment.setTvQueryCount();
}
}
主界面XML代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:qit="http://schemas.android.com/apk/res/com.qit.iword"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</android.support.v4.view.ViewPager>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@drawable/tab_background"
android:orientation="horizontal" >
<com.qit.iword.TabIcon
android:id="@+id/tab_one"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="5dp"
qit:tab_color="#FD805B"
qit:tab_icon="@drawable/tab_intercept"
qit:tab_text="翻译"
qit:tab_text_size="12sp" />
<com.qit.iword.TabIcon
android:id="@+id/tab_two"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="5dp"
qit:tab_color="#FD805B"
qit:tab_icon="@drawable/tab_daily"
qit:tab_text="每句"
qit:tab_text_size="12sp" />
<com.qit.iword.TabIcon
android:id="@+id/tab_three"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="5dp"
qit:tab_color="#FD805B"
qit:tab_icon="@drawable/tab_recite"
qit:tab_text="发现"
qit:tab_text_size="12sp" />
<com.qit.iword.TabIcon
android:id="@+id/tab_four"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="5dp"
qit:tab_color="#FD805B"
qit:tab_icon="@drawable/tab_me"
qit:tab_text="我的"
qit:tab_text_size="12sp" />
</LinearLayout>
</LinearLayout>
tab_bg样式(新建drawable>tab_bg.xml)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke
android:width="1.5dp"
android:color="#eee" />
<solid android:color="#f7f7f7" />
</shape>
命名空间(values>attr.xml)
<attr name="tab_icon" format="reference"></attr>
<attr name="tab_color" format="color"></attr>
<attr name="tab_text" format="string"></attr>
<attr name="tab_text_size" format="dimension"></attr>
<declare-styleable name="TabIcon">
<attr name="tab_icon"></attr>
<attr name="tab_color"></attr>
<attr name="tab_text"></attr>
<attr name="tab_text_size"></attr>
</declare-styleable>
图标渐变效果参考Hyman老师的文章
其实底部效果无非就是这张图
讲解一下:如同上图,现在我们假设有两张图片Src和Dst,当我们把两张图拼在一起的时候会有后面13种情况,拿我们要用到的DstIn举例,”重合部分显示Dst”就会出现那个样式,同理可得其他.
那么就很好理解了 我底下放一个有颜色的控件,上面放一张透明背景的图标,当样式为DstIn时,两方重合部分显示颜色,就得到前面此效果了,至于渐变无非就是透明度随移动而变化.
书写TabIcon类来自定义这种View
public class TabIcon extends View {
private int mColor = 0xff45c01a;
private Bitmap mIconBitmap;
private String mText = "iWord";
private int mTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12,
getResources().getDisplayMetrics());
private Canvas mCanvas;
private Bitmap mBitmap;
private Paint mPaint;
private float mAlpha;
private Rect mIconRect;
private Rect mTextBound;
private Paint mTextPaint;
public TabIcon(Context context) {
this(context, null);
}
public TabIcon(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* 获取自定义属性的值
*
* @param context
* @param attrs
* @param defStyleAttr
*/
public TabIcon(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabIcon);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.TabIcon_tab_icon:
BitmapDrawable drawable = (BitmapDrawable) a.getDrawable(attr);
mIconBitmap = drawable.getBitmap();
break;
case R.styleable.TabIcon_tab_color:
mColor = a.getColor(attr, mColor);
break;
case R.styleable.TabIcon_tab_text:
mText = a.getString(attr);
break;
case R.styleable.TabIcon_tab_text_size:
mTextSize = (int) a.getDimension(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12,
getResources().getDisplayMetrics()));
break;
}
}
a.recycle();
mTextBound = new Rect();
mTextPaint = new Paint();
mTextPaint.setTextSize(mTextSize);
mTextPaint.setColor(0xff555555);
mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int iconWidth = Math.min(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
getMeasuredHeight() - getPaddingTop() - getPaddingBottom() - mTextBound.height());
int left = getMeasuredWidth() / 2 - iconWidth / 2;
int top = getMeasuredHeight() / 2 - (mTextBound.height() + iconWidth) / 2;
mIconRect = new Rect(left, top, left + iconWidth, top + iconWidth);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mIconBitmap, null, mIconRect, null);
int alpha = (int) Math.ceil(255 * mAlpha);
setupTargetBitmap(alpha);
drawSourceText(canvas, alpha);
drawTargetText(canvas, alpha);
canvas.drawBitmap(mBitmap, 0, 0, null);
}
/**
* 绘制变色文本
*
* @param canvas
* @param alpha
*/
private void drawTargetText(Canvas canvas, int alpha) {
mTextPaint.setColor(mColor);
mTextPaint.setAlpha(alpha);
int x = getMeasuredWidth() / 2 - mTextBound.width() / 2;
int y = mIconRect.bottom + mTextBound.height();
canvas.drawText(mText, x, y, mTextPaint);
}
/**
* 绘制文本
*
* @param canvas
* @param alpha
*/
private void drawSourceText(Canvas canvas, int alpha) {
mTextPaint.setColor(0xff333333);
mTextPaint.setAlpha(255 - alpha);
int x = getMeasuredWidth() / 2 - mTextBound.width() / 2;
int y = mIconRect.bottom + mTextBound.height();
canvas.drawText(mText, x, y, mTextPaint);
}
/**
* 绘制可变色Icon
*
* @param alpha
*/
private void setupTargetBitmap(int alpha) {
mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPaint = new Paint();
mPaint.setColor(mColor);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setAlpha(alpha);
mCanvas.drawRect(mIconRect, mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setAlpha(255);
mCanvas.drawBitmap(mIconBitmap, null, mIconRect, mPaint);
}
public void setIconAlpha(float alpha) {
this.mAlpha = alpha;
invalidateView();
}
/**
* 重绘
*/
private void invalidateView() {
if (Looper.getMainLooper() == Looper.myLooper()) {
invalidate();
} else {
postInvalidate();
}
}
private static final String INSTANCE_STATUS = "instance_status";
private static final String STATUS_ALPHA = "status_alpha";
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(INSTANCE_STATUS, super.onSaveInstanceState());
bundle.putFloat(STATUS_ALPHA, mAlpha);
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if(state instanceof Bundle){
Bundle bundle = (Bundle) state;
mAlpha = bundle.getFloat(STATUS_ALPHA);
super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATUS));
return;
}
super.onRestoreInstanceState(state);
}
}
再说一遍,颜色渐变代码属于完全抄袭完全,呵呵哒…
好主界面tab的UI就完成了,下一篇实现第一个fragment查词.