GooglePlay开发笔记

  1. 页签使用PagerTab。使用PagerTab时,setOnPageChangeListener需要绑定在pageTab上。否则会出现滑动异常。(why?)

2.在ViewPager中添加Fragment,使用FragmentPagerAdapter。getSupportFragmentManager()只有在FragmentActivity中才可调用,AppCompatActivity是继承于FragmentActivity的。

3.使用string.xml中的数组时,使用代码

context.getResources().getStringArray(R.array.arrayname);

4.使用工厂模式,创建Fragment。

通过position去创建Fragment,创建好的fragment放入Map中,要使用的时候不需要重新创建,只需要拿出来使用即可。代码如下:

 //通过position创建Fragment,然后将创建的Fragment装到Map中。
    private static ArrayMap<Integer,BaseFragment> map = new ArrayMap<>();
    public static BaseFragment createFragment(int position){
        BaseFragment baseFragment = map.get(position);
        if(baseFragment==null){
            switch (position){
                case 0:
                    baseFragment = new HomeFragment();
                    break;
                case 1:
                    baseFragment = new AppFragment();
                    break;
                case 2:
                    baseFragment = new GameFragment();
                    break;
                case 3:
                    baseFragment = new SubjectFragment();
                    break;
                case 4:
                    baseFragment = new RecommendFragment();
                    break;
                case 5:
                    baseFragment = new CategoryFragment();
                    break;
                case 6:
                    baseFragment = new HotFragment();
                    break;
            }
            map.put(position,baseFragment);
        }
        return baseFragment;
    }

5.主题问题。

如果项目的BaseActivity继承了AppCompatActivity,那么项目的主题一定要是Theme.AppCompat的。否则就会崩溃。

6.在BaseFragment中有这样的逻辑,根据网络情况显示不同的页面,加载失败,数据为空,加载中,加载成功,这几种情况显示的页面不同。

思路: 创建一个FrameLayout,命名为LoadingView,往这个LoadingView中添加4个页面, 分别是errorView,loadingView,emptyView,successView,根据网络情况的不同显示不同的页面。successView的情况特殊一点,为了避免资源浪费,就是只有在加载成功情况下才会去创建successView。而每个子类加载成功的页面不同,所以createSuccessView()要写成抽象方法,供子类重写。
在BaseFragment中使用LoadingView:

public abstract class BaseFragment extends Fragment {

    private LoadingView loadingView;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        loadingView = new LoadingView(UIUtils.getContext()){

            @Override
            public View createSuccessView() {
                return fragmentCreateSuccessView();
            }
        };
        return loadingView;
    }

    public abstract View fragmentCreateSuccessView();

}

其中抽象方法:fragmentCreateSuccessView()是供子类重写的。

7.自定义进度条。

两张图片叠加使用drawable文件的根节点是:layer-list ,再在其中添加动画。使用,在ProgressBar中添加属性:android:indeterminateDrawable 将drawable文件赋值给该属性即可。

7.1 设置动画属性文件

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--此标签表示几张图片叠加-->
    <!--第一张图片-->
<item>
    <rotate
        android:drawable="@drawable/spinner_big_inner"
        android:fromDegrees="0"
        android:toDegrees="720"
        android:pivotY="50%"
        android:pivotX="50%"/>
</item>
    <!--第二张图片-->
    <item>
        <rotate
            android:drawable="@drawable/spinner_big_outer"
            android:fromDegrees="720"
            android:toDegrees="0"
            android:pivotX="50%"
            android:pivotY="50%"/>
    </item>
</layer-list>

7.2 使用

 <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:indeterminateDrawable="@drawable/custom_loading"/>

8.获取当前类名

getClass().getSimpleName();

9.ListView的封装
9.1 封装BaseHolder

/**
 * Created by kimliu on 2018/5/27.
 * ListView 中 ViewHolder的父类
 *
 * 在ListView的Adapter中 getView()中要使用到ViewHolder
 * 而ViewHolder的作用,是用来
 * 1.初始化Item 布局文件
 * 2.findViewById 找到布局文件中的控件
 * 3.打一个tag
 * 4.根据数据,更新UI 也就是把数据填充到UI中
 *
 * 因此 封装的BaseHolder 就必须完成这四步,无法确定的 比如初始化Item布局文件,
 * 就写一个抽象方法,交给子类去做
 */

public abstract class BaseHolder<T> {

    private  View mRootView;
    private T data;//Item对应的数据

    /**
     * 在构造方法中就initView
     */
    public BaseHolder(){
        mRootView = initView();
        mRootView.setTag(this);//3.给View设置Tag
    }

    /**
     * 1.初始化Item布局文件
     * 2. findViewById 找到布局中的控件
     *  这两步父类无法实现,需要交给子类去实现
     * @return
     */

    public abstract View initView();

    /**
     * 外界拿到布局对象的方法
     */
    public View getRootView(){
        return mRootView;
    }


    /**
     * 4.刷新界面,将数据设置给控件
     * 这个方法在各个子类中的实现也各不相同,因此也需要交由子类去完成
     */
    public abstract void refreshView(T data);


    /**
     * 外界将数据传递进来的方法
     */
    public void setData(T data){
        this.data = data;
        //一拿到data 立即用上
        refreshView(data);
    }
    
    public T getData(){
        return data;
    }

}

9.2 封装BaseAdapter

/**
 * Created by kimliu on 2018/5/27.
 * ListView 的 Adapter 的封装
 *
 */

public abstract class MyBaseAdapter<T> extends BaseAdapter {


    private ArrayList<T> data;
    public void setData(ArrayList<T> data){
        this.data = data;
    }


    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public T getItem(int position) {
        return data.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        BaseHolder holder ;
        if(convertView == null){
            //此时如果添加new 出一个需要的Holder 那么 initView 和 findViewById 都完成了
            //但是我们并不知道需要的Holder是什么类型的,因此可以交给子类完成
            //创建抽象方法,由子类重写
            holder = getHolder();

        }else {
            holder = (BaseHolder) convertView.getTag();
        } 

        holder.setData(getItem(position));//设置数据
        return holder.getRootView();
    }
    public abstract BaseHolder<T> getHolder();
}

9.3 封装之后的使用,只需要new 出需要的Holder 继承BaseHolder 在子类的initView中进行 inflate 和 findViewById的操作,在refreshView中进行data的赋值即可。

如:Adapter

 class HomeAdapter extends MyBaseAdapter<String>{

        @Override
        public BaseHolder<String> getHolder() {
            return new HomeHolder();
        }
    }

ViewHolder:

/**
 * Created by kimliu on 2018/5/27.
 */

public class HomeHolder extends BaseHolder<String> {

    private TextView textView;

    @Override
    public View initView() {
        textView = new TextView(UIUtils.getContext());
        return textView;
    }

    @Override
    public void refreshView(String data) {
        textView.setText(data);
    }
}

这是最基础的ListView的封装。

10.封装加载更多ListView。
思路:展示两种布局,第一种 普通布局,第二种,加载更多布局。加载更多布局是在position == getCount()-1时显示。
10.1.在MyBaseAdapter中添加两个方法,这两个方法是ListView显示不同布局必须要重写的两个方法:

/**
 * 返回要加载的布局类型,有几种就返回几种
 * @param position
 * @return
 */
@Override
public int getItemViewType(int position) {
    if(position == getCount()-1){
        //最后一个 加载更多类型
        return TYPE_MORE;
    }else{
        return getType();
    }

}

/**
 * 子类可能不止有普通类型 还有可能有别的类型,这里提供一个可以更改的入口
 *
 * 不写成抽象方法,子类如果有更多的类型就重写,没有就直接返回普通类型
 * @return
 */
public  int getType(){
    return TYPE_NOMAL;
}

/**
 * 将来子类也可重写该方法 返回有几种type
 * @return
 */
@Override
public int getViewTypeCount() {
    return 2;
}

10.2. 在getView()中 根据Type设置布局,当type为TYPE_MORE时,设置加载更多布局,其它设置普通布局。

if(getItemViewType(position) == TYPE_MORE){
    //是加载更多类型
    holder = new MoreHolder();
}else{

    //此时如果添加new 出一个需要的Holder 那么 initView 和 findViewById 都完成了
    //但是我们并不知道需要的Holder是什么类型的,因此可以交给子类完成
    //创建抽象方法,由子类重写
    holder = getHolder();
}

10.3. 加载更多布局,要根据状态去刷新界面。
加载更多有几种状态:1.可以加载更多,2.加载失败 3.不需要加载更多 根据这几种状态去刷新界面。
可以在MoreHolder的构造方法中传入一个boolean类型的值,如果为true 则为可以加载更多 如果为false 则为不需要加载更多的状态 那么就可以setData(int) 在MoreHolder中setData,设置的是int类型的状态,因为BaseHolder是根据传入的值去刷新界面的,而MoreHolder是根据状态刷新界面,所以这里MoreHolder的泛型就为Integer。

public class MoreHolder extends BaseHolder<Integer> {


    public static final int LOAD_MORE_MORE = 0;
    public static final int LOAD_MORE_ERROR = 1;
    public static final int LOAD_MORE_NONE = 2;
    private LinearLayout ll_more;
    private TextView tv_error;


    public MoreHolder(boolean hasMore) {
        setData(hasMore?LOAD_MORE_MORE:LOAD_MORE_NONE);

    }

    @Override
    public View initView() {
        View view = KimliuUtils.inflate(UIUtils.getContext(), R.layout.item_more);
        ll_more = view.findViewById(R.id.ll_more);
        tv_error = view.findViewById(R.id.tv_error);
        return view;
    }

    @Override
    public void refreshView(Integer data) {
        switch (data){
            case LOAD_MORE_MORE:
                //加载更多
                ll_more.setVisibility(View.VISIBLE);
                tv_error.setVisibility(View.GONE);
                break;
            case LOAD_MORE_ERROR:
                //加载失败
                ll_more.setVisibility(View.GONE);
                tv_error.setVisibility(View.VISIBLE);
                break;
            case LOAD_MORE_NONE:
                //不需要加载更多
                ll_more.setVisibility(View.GONE);
                tv_error.setVisibility(View.GONE);
                break;

        }

    }

10.4.界面已经写完了,现在就要开始加载数据了。
10.4.1 在MyBaseAdapter中写一个方法 onLoadMore()加载更多,具体代码中已注释

 private boolean isLoadMore = false;
    public void onLoadMore(final MoreHolder moreHolder){
        if(!isLoadMore){
            //只有当isLoadMore为false才会进来
            new Thread(){
                @Override
                public void run() {
                    isLoadMore = true;
                    //开启一个子线程,进行数据的加载
                    moreList = loadMore();

                    UIUtils.runOnUIThread(new Runnable() {
                        @Override
                        public void run() {
                            //根据moreList去刷新界面,刷新界面需要在主线程中去完成
                            if(moreList!=null){
                                if(moreList.size() < limtNum()){
                                    //每一页为limtNum条数据,如果 < limtNum()了,说明到最后一页了
                                    moreHolder.setData(MoreHolder.LOAD_MORE_NONE);
                                    Toast.makeText(UIUtils.getContext(),
                                            "没有更多数据了", Toast.LENGTH_SHORT)
                                            .show();
                                }else {
                                    // 还有更多数据
                                    moreHolder.setData(MoreHolder.LOAD_MORE_MORE);
                                }

                                //根据加载更多的结果去刷新页面
                                // 将更多数据追加到当前集合中
                                data.addAll(moreList);
                                // 刷新界面
                                MyBaseAdapter.this.notifyDataSetChanged();

                            }else{
                                //如果moreList 为空,说明加载失败
                                moreHolder.setData(MoreHolder.LOAD_MORE_ERROR);
                            }

                            //加载完毕,将isLoadMore改为false
                            isLoadMore = false;
                        }
                    });


                }
            }.start();
        }

    }

    /**
     * 如果每页显示的条数不为20 那么子类重写
     * @return
     */
    public int limtNum(){
        return 20;
    }


    /**
     * 每个子类加载更多的情况不同,所有交由子类重写
     * @return
     */
    public abstract ArrayList<T> loadMore();

加载更多的方法已经写好,我们在什么时候调用呢?
10.4.2 调用加载更多的方法,我们需要在加载更多布局显示的时候调用onLoadMore(),对ListView来说,item显示的时候,一定会调用getView方法,在getView方法中判断Type 如果Type == TYPE_MORE,说明此时需要加载更多,同时我们需要进一步的判断,加载更多布局此时的状态,如果状态为LOAD_MORE_MORE,才会去加载更多。

if(getItemViewType(position) == TYPE_NOMAL){
            holder.setData(getItem(position));//设置数据
        }else{
            //当ListView的Item显示时,必定会调getView方法,
           //因此,当getItemViewType(position) == TYPE_MORE
            //时,也就是加载更多布局显示的时候,我们需要调用//
        //onLoadMore(),而此时的holder 正是moreHolder
            MoreHolder moreHolder = (MoreHolder) holder;
            if(moreHolder.getData() == MoreHolder.LOAD_MORE_MORE){
                //当moreHolder状态为可以加载更多时,才去加载更多
                onLoadMore(moreHolder);
            }
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值