Android中顶部Tab带滑动选项卡之二选一,仿淘宝宝贝收藏和店铺收藏

周末刚过,对于礼拜一可能大家的心情还沉浸在周末那种放松的那种状态下。我也是。出于无聊,随便翻看了一下之前写过的一个商城类项目,来这里和大家分享其中的一个小功能,就当是练练手,进入工作状态。

在这里声明一下,由于本人属于一个典型的懒程序员,文字叙述也不是很好。能写博客已经是极限了,哈哈。所以以后我的博客习惯都是先看效果图然后在看具体代码和实现。(因为我实在不想用文字去叙述一个功能效果)好了,手指已经很累了,打这么字确实很不容易,小时候作文经常挨老师批评,上图吧


Android中顶部Tab带滑动选项卡之二选一,仿淘宝宝贝收藏和店铺收藏_第1张图片
相信大家看到了,这种类似的需求在开放中还是很常见的,其实实现的方式也很多,今天我们来学习一下它是如何实现的。

首先梳理一下,用到的知识点,ViewPager,Fragment,BitmapFactory,Matrix

具体的不再详细介绍了,代码里面注释写的比较详细。

- 首先我们先创建两个fragment。分别作为 宝贝,店铺的布局界面

package achoice.com.taba;

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;

/**
 * 作者:${NanFeiLong}
 * 日期 2016/12/9 17:26
 * 宝贝对应的fragment
 */

public class BaoBeiFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.baobei,container,false);
        return view;
    }


}
  • 对应的layout文件baobei.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:gravity="center">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:textSize="24dp"
        android:padding="15dp"
        android:textColor="#969696"
        android:text="您还没有收藏任何宝贝哦!"/>
LinearLayout>

店铺的Fragment和布局文件也类似。因为两个基本相同,这里就不用给出了,有兴趣的可以下载源码。

  • 下来是MainActivity,这里我们让其继承自FragmentActivity点击事件和滑动事件都用实现接口的方式去实现监听
package achoice.com.taba;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends FragmentActivity implements View.OnClickListener, ViewPager.OnPageChangeListener {
    // ViewPager适配器
    private ViewPager mViewPager;
    private FragmentAdapter mFragmentAdapter = null;
    private int tabWidth;
    private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
    //图片选择条
    private ImageView mivBottom_line;
    // 宝贝
    private TextView mtvBaoBei;
    // 店铺
    private TextView mtvStore;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mViewPager = (ViewPager) findViewById(R.id.viewpager);
        mivBottom_line = (ImageView) findViewById(R.id.img_tabLine);
        mtvBaoBei = (TextView) findViewById(R.id.tv_baobei);
        mtvStore = (TextView) findViewById(R.id.tv_store);
        mtvBaoBei.setTextColor(getResources().getColor(R.color.checked_textcolor));
        //图片选择条
        initData();
        mFragmentAdapter = new FragmentAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(mFragmentAdapter);
        mtvBaoBei.setOnClickListener(this);
        mtvStore.setOnClickListener(this);
        mViewPager.setOnPageChangeListener(this);

    }

    /**
     * 配置图片选择条
     */
    private void initData() {
        getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
        tabWidth = mDisplayMetrics.widthPixels / 2;
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bottom_line);
        // 设置图片选择条的宽高
        Bitmap bitmap1 = Bitmap.createBitmap(bitmap, 0, 0, tabWidth, 8);
        mivBottom_line.setImageBitmap(bitmap1);
    }

    /**
     * 点击监听
     *
     * @param view
     */
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            // 宝贝
            case R.id.tv_baobei: {
                TextTab();
                mtvBaoBei.setTextColor(getResources().getColor(R.color.checked_textcolor));
                mViewPager.setCurrentItem(0);
            }
            break;
            // 店铺
            case R.id.tv_store: {
                TextTab();
                mtvStore.setTextColor(getResources().getColor(R.color.checked_textcolor));
                mViewPager.setCurrentItem(1);
            }
            break;
            default:
                break;
        }
    }

    /**
     * 正在滑动时
     * @param position
     * @param positionOffset 当前页面偏移的百分比[0,1)
     * @param positionOffsetPixels 当前页面偏移的像素位置
     */
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        // Matrix创建一个矩形
        Matrix matrix = new Matrix();
        switch (position) {
            case 0:
                // 使用setTranslate直接位置
                matrix.setTranslate(0, 0);
                break;
            case 1:
                matrix.setTranslate(tabWidth, 0);
                break;
        }
        // 在滑动的过程中,计算出图片选择条的动态滑动距离
        //这里用了"后乘"positionOffset[0,1)
        float miters = (tabWidth) * positionOffset;
        // 使用postTranslate动态追加滑动距离
        matrix.postTranslate(miters, 0);
        mivBottom_line.setImageMatrix(matrix);
    }

    /**
     * 滑动完毕时
     * @param position  滑动完毕时 停留在的页面
     */
    @Override
    public void onPageSelected(int position) {
        switch (position) {
            case 0: {
                TextTab();
                mtvBaoBei.setTextColor(getResources().getColor(R.color.checked_textcolor));
                mViewPager.setCurrentItem(0);
            }
            break;
            case 1: {
                TextTab();
                mtvStore.setTextColor(getResources().getColor(R.color.checked_textcolor));
                mViewPager.setCurrentItem(1);
            }
            break;
            default:
                break;
        }
    }


    @Override
    public void onPageScrollStateChanged(int state) {

    }


    /**
     * 文字全部重置为默认状态
     */
    private void TextTab() {
        mtvBaoBei.setTextColor(getResources().getColor(R.color.default_color));
        mtvStore.setTextColor(getResources().getColor(R.color.default_color));
    }


}

这里大概说一下,viewpager的滑动和fragment的切换,这些没什么说的,关键点比较绕的是下面的图片选择滑动条的处理。

  1. 首先
    我们对图片宽高进行适配,这里高度我们在xml中设置了,宽度占用手机屏幕的1/2。
    调用 tabWidth = mDisplayMetrics.widthPixels / 2;
  2. 然后
    我们在重写的onPageScrolled(当滑动进行时)方法中调用Matrix 绘制一个矩形。在调用matrix.setTranslate(tabWidth, 0);方法实现图片滑动条位置。其实就是通过计算平移距离来实现确定位置的。对于动态中图片滑动条的位置,我们来分析这几行代码
      float miters = (tabWidth) * positionOffset;
        // 使用postTranslate动态追加滑动距离
        matrix.postTranslate(miters, 0);
        mivBottom_line.setImageMatrix(matrix);

positionOffset参数为viewpager在滑动时的偏移量取值[0,1),tabWidth图片滑动条的宽度,这里也就是屏幕的1/2。这样我们就能得到图片滑动时的动态”宽度”了。
得到动态”宽度”后,然后在调用Matrix的postTranslate(float dx, float dy)方法。这个方法的叫做”后乘”,可能大家对这个比较陌生,其实我刚开始看到后也是理解不了,这里写图片描述不过没关系,这里我给大家推荐一篇文章Android之Matrix的用法 。其实就是每次的平移完成后状态保持然后继续下一次平移得到最后一次的平移位置。比如说第一次平移到(0.5,0)位置,停止下来,第二次平移到(0.6,0)位置停止下来,那么最后我们看到的结果是显示停留在(0.6,0)位置的图片的。

3.最后
我们还写了一个TextTab()方法。其作用就是每当点击选项卡或者滑动页面时候,都先把选项卡文字都设置成位选中颜色状态,然后根据position在设置其选中状态时候对应的选项卡颜色和状态。

/**
     * 文字全部重置为默认状态
     */
    private void TextTab() {
        mtvBaoBei.setTextColor(getResources().getColor(R.color.default_color));
        mtvStore.setTextColor(getResources().getColor(R.color.default_color));
    }
  • 布局文件activity_main.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#f1f1f1"
    android:orientation="vertical"
    tools:context="achoice.com.taba.MainActivity">

    <LinearLayout
        android:id="@+id/llyout_my_coupon_sort"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tv_baobei"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="#f8f8f8"
            android:paddingTop="10dp"
            android:paddingBottom="15dp"
            android:gravity="center"
            android:text="宝贝(0)"
            android:textStyle="bold"
            android:textSize="16sp"/>

        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="5dp"
            android:background="#d7d7d7"/>

        <TextView
            android:id="@+id/tv_store"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="#f8f8f8"
            android:paddingTop="10dp"
            android:paddingBottom="15dp"
            android:gravity="center"
            android:textStyle="bold"
            android:text="店铺(0)"
            android:textSize="16sp"/>
    LinearLayout>

    <ImageView
        android:id="@+id/img_tabLine"
        android:layout_width="match_parent"
        android:layout_height="3dp"
        android:contentDescription="@null"
        android:scaleType="matrix"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="0.3dp"
        android:layout_marginBottom="5dp"
        android:background="#d7d7d7"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>


LinearLayout>
  • 还有colors.xml

<resources>
    <color name="colorPrimary">#3F51B5color>
    <color name="colorPrimaryDark">#303F9Fcolor>
    <color name="colorAccent">#FF4081color>


    <color name="textcolor_mine_normal">#666666color>
    <color name="checked_textcolor">#f56a30color>
    <color name="default_color">#898787color>
resources>
好了,就说到这里,项目已经上传,有兴趣的可以下载源码

源码

你可能感兴趣的:(Android)