Android Design Support Library 02 — CollapsingToolbarLayout&&CardView

 更新时间:2016年9月20日 19:54  点击:1710
下面我们一起来看一篇Android Design Support Library 02 — CollapsingToolbarLayout&&CardView问题解决办法。

Material Design的第二篇更新啦!这次介绍两个控件CollapsingToolbarLayout&&CardView

1、CollapsingToolbarLayout

5.0之后,折叠效果的App出现了,前段时间google在material design的设计中也推出了这个控件。
Ok,还是先上视频!

 代码如下 复制代码
<android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="256dp"
        android:fitsSystemWindows="true">
        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:contentScrim="#30469b"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">
  
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@mipmap/bg"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="0.7"  />
  
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin" />
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

官方提示,使用CollasingToolbarLayout和Toolbar,title用CollapsingToolbar来设置
This setup uses CollapsingToolbarLayout’s app:layout_collapseMode=”pin” to ensure that the Toolbar itself remains pinned to the top of the screen while the view collapses. Even better, when you use CollapsingToolbarLayout and Toolbar together, the title will automatically appear larger when the layout is fully visible, then transition to its default size as it is collapsed. Note that in those cases, you should call setTitle() on the CollapsingToolbarLayout, rather than on the Toolbar itself.

2、CardView

实现了卡片式的并且有阴影效果。

 代码如下 复制代码

<android.support.v7.widget.CardView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_margin="@dimen/card_margin">
 
       <LinearLayout
           style="@style/Widget.CardContent"
           android:layout_width="match_parent"
           android:layout_height="wrap_content">
 
           <TextView
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="界冢伊奈帆(かいづか いなほ)"
               android:textAppearance="@style/TextAppearance.AppCompat.Title" />
 
           <TextView
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="主人公。居住在地..." />
 
           <ImageView
               android:id="@+id/iv_ynf"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content" />
 
       </LinearLayout>
</android.support.v7.widget.CardView>

下面我们一起来看一篇关于 解决:Bitmap too large to be uploaded into a texture exception问题解决办法。

最近做项目发现其他手机没有问题,但是出现了一个手机报异常,最难过的是不显示报错信息,弄了很久,才发现了一句话:Bitmap too large to be uploaded into a texture exception,百度一下才知道怎么回事。简单说就是硬件加速的时候,对图片的大小有限制。不同设备可能有不同的最大值。这个问题悲催的地方是,程序貌似没有捕获到这个exception, 结果是程序也不报错,图片也显示不出来。只有看debug log才能发现这个error message.

一个解决的方法是禁止硬件加速,简单粗暴:

 代码如下 复制代码


<application android:hardwareAccelerated="false" ...>

比较好的解决方法是类似google map的实现:将图片分成不同的块,每次加载需要的块。android提供了一个方法:

http://developer.android.com/reference/android/graphics/BitmapRegionDecoder.html

 代码如下 复制代码


public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)
public Bitmap decodeRegion (Rect rect, BitmapFactory.Options options)

采取上述操作后,就可以加载很多图片,同时也可以显示超级大图了。

还有用ImageLoad加载图片,如果出现这个问题我们可以这样处理:

可以对ImageView设置最大高度和最大宽度:

 

 代码如下 复制代码
android:maxHeight="1000dip"
 
android:maxWidth="1000dip"

同时相应的scaleType为FIT_CENTER  FIT_XY   FIT_START FIT_END CENTER_INSIDE

在上面这些scaleType下,当bitmap的高和宽一个大于所设的最大值时,imageloader会自动处理,按比例缩放。当scaleType为 MATRIX  CENTER  CENTER_CROP时  要高宽两者都大于所设的最大值时,imageloder才会处理。

Android开发语言是Java,所以也分主线程、子线程,那么我们如何要主线程来向子线程发送消息,希望子线程来处理,该如何实现呢?

有时候,我们也可能碰到这样子的一种需求:需要主线程来向子线程发送消息,希望子线程来完成什么任务。如果这样子应该怎么做呢?这就是这篇文章将要讨论的内容。

一、HandlerThread类

主线程发送消息给子线程,通常思维逻辑就是:其实很简单,在主线程中实例化一个Handler,然后让他与子线程相关联(只要它与子线程的Looper相关联即可),这样子它处理的消息就是该子线程中的消息队列,而处理的逻辑都是在该子线程中执行的,不会占用主线程的时间。那么我们就来实现一下,看看这样子到底行得通还是行不通。新建项目,修改它的MainActivity的代码,如下即可:

package com.example.handldertest;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.TextView;
public class ThreadHandlerActivity extends Activity{
    
    //创建子线程
    class MyThread extends Thread{
        private Looper looper;//取出该子线程的Looper
        public void run() {
         
            Looper.prepare();//创建该子线程的Looper
            looper = Looper.myLooper();//取出该子线程的Looper
            Looper.loop();//只要调用了该方法才能不断循环取出消息
        }
    }
    
    private TextView tv;
    private MyThread thread;
    
    
    private Handler mHandler;//将mHandler指定轮询的Looper
    
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            tv = new TextView(this);
            tv.setText("Handler实验");
            setContentView(tv);
            thread = new MyThread();
            thread.start();//千万别忘记开启这个线程
            //下面是主线程发送消息
            mHandler = new Handler(thread.looper){
                public void handleMessage(android.os.Message msg) {
                    Log.d("当前子线程是----->", Thread.currentThread()+"");
                };
            };
            mHandler.sendEmptyMessage(1);
    }
}


好了,现在运行该程序。有没有得到预期的结果呢?显然没有,因为报错误了,如下:


这是一个空指针错误。这是为什么呢?仔细思考,也不难发现原因。因为当主线程走到第38行时,此时子线程的Looper对象还没有被创建出来,那么此时thread.looper肯定为空了。其实这个时间是很不好控制的,当然了,你可以让主线程休眠2秒后再执行第38行以后的代码。但是如果有很多个子线程都需要主线程类给其分配任务怎么办??那简直要乱套了。所以我们就更好的解决方式。就是android显然也考虑到了这个问题,于是它我们提供了一个HandlerThread类。这个类是专门处理这个问题的。

当主线程中有耗时的操作时,需要在子线程中完成,通常我们就把这个逻辑放在HandlerThread的对象中执行(该对象就是一个子线程),然后在需要开始执行逻辑的地方发送一个Message来通知一下就可以了。下面我们就修改上面的代码,看一看如何使用HandlerThread这个类。修改MainActivity中的代码如下:

package com.example.handldertest;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.widget.TextView;
public class ThreadHandlerActivity extends Activity{
    
    
    private TextView tv;
    private Handler mHandler;//将mHandler指定轮询的Looper
    
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            tv = new TextView(this);
            tv.setText("Handler实验");
            setContentView(tv);
        
            //实例化一个特殊的线程HandlerThread,必须给其指定一个名字
            HandlerThread thread = new HandlerThread("handler thread");
            thread.start();//千万不要忘记开启这个线程
            //将mHandler与thread相关联
            mHandler = new Handler(thread.getLooper()){
                public void handleMessage(android.os.Message msg) {
                    Log.d("当前子线程是----->", Thread.currentThread()+"");
                };
            };
            mHandler.sendEmptyMessage(1);//发送消息
    }
}


运行程序,打印的结果如下:


从打印结果来看,当前子线程的名字正是我们所起的那个名字“handler thread"。

你会有疑问,表面上看HandlerThread并没有创建自己的Looper啊?而且既然是一个线程,那么我们肯定也能重写它的run方法吧。在解答你的疑问之前,我们不妨重写它的run方法来看一看会有什么结果。将代码修改如下:

package com.example.handldertest;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.widget.TextView;
public class ThreadHandlerActivity extends Activity{
    
    
    private TextView tv;
    private Handler mHandler;//将mHandler指定轮询的Looper
    
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            tv = new TextView(this);
            tv.setText("Handler实验");
            setContentView(tv);
        
            //实例化一个特殊的线程HandlerThread,必须给其指定一个名字
            HandlerThread thread = new HandlerThread("handler thread"){
                @Override
                public void run() {
                    for(int i=0;i<3;i++){
                        Log.d("handler thread run ",i+"");
                    }
                }
            };
//            HandlerThread thread = new HandlerThread("handler thread");
            thread.start();//千万不要忘记开启这个线程
            //将mHandler与thread相关联
            mHandler = new Handler(thread.getLooper()){
                public void handleMessage(android.os.Message msg) {
                    Log.d("当前子线程是----->", Thread.currentThread()+"");
                };
            };
            mHandler.sendEmptyMessage(1);//发送消息
    }
}


红色部分就是我们重写了它的run方法。再云运行程序,打印的结果如下:

for循环的打印结果正常,但是为什么没有打印出”当前子线程“呢。其实这正是我们要解释的地方。还记得上一篇文章中实现与子线程相关联的的Handler,我们是怎么做的吗?没读过的朋友看以点击链接(http://www.cnblogs.com/fuly550871915/p/4889838.html)。其实我们实现Handlei与线程的关联正是写在run方法中的。而对于HandlerThread这样的线程,也是如此。我们翻看这个类的源代码,找到它的run方法,如下:

@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    

在源代码的第4行,进行了实例化自己的Looper,如果继续追踪源代码翻看其getLooper方法你会发现,如果一个Handler在与HandlerThread进行绑定时,发现Looper为空,Handler则会一直等待直到Looper被创建出来为止,然后才继续执行后续的代码。所以我们重写了HandlerThread的run方法,肯定就不会去创建Looper对象,那么绑定的Handler就会永远处于等待状态,自然而然就不会打印出”当前子线程“信息了。这也是为什么我们要使用HandlerThread这个特殊的线程,因为使用这个,我们不必关心多线程会混乱,Looper会为空等一系列问题,只要去关心我们要实现的逻辑就行了。

好了,现在做一下简单的总结吧。

 小结:
1. Handler与哪个线程的Looper相关联,那么它的消息处理逻辑就在与之相关的线程中执行,相应的消息的走向也就在相关联的MessageQueue中。(最常见的就是Handler与主线程关联,那么接收Looper回传的消息后的逻辑就会在主线程中执行)
2. 当主线程中需要与子线程进行通信时(比如将耗时操作放在子线程中),建议使用HandlerThread。同时要注意,千万不要去重写它的run方法。

二、一个主线程与子线程互相通信的例子

知识点都说完了。下面我们来写一个具体的例子实践一下吧。新建一个项目,修改它的MainActivity代码,如下:

package com.example.handldertest;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.widget.TextView;
public class ThreadHandlerActivity extends Activity{
    
    
    private TextView tv;
    private Handler mHandler;//与子线程关联的Handler
    private Handler handler;//与主线程关联的Handler
    
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            tv = new TextView(this);
            tv.setText("Handler实验");
            setContentView(tv);
        
            //实例化一个特殊的线程HandlerThread,必须给其指定一个名字
            HandlerThread thread = new HandlerThread("handler thread");
            thread.start();//千万不要忘记开启这个线程
            //将mHandler与thread相关联
            mHandler = new Handler(thread.getLooper()){
                public void handleMessage(android.os.Message msg) {
                    Log.d("我是子线程----->", Thread.currentThread()+"");
                    handler.sendEmptyMessage(1);//发送消息给主线程
                };
            };
            
            handler = new Handler(){
                public void handleMessage(android.os.Message msg) {
                    Log.d("我是主线程----->", Thread.currentThread()+"");
                    mHandler.sendEmptyMessage(1);//发送消息给子线程
                };
            };
            mHandler.sendEmptyMessage(1);//发送消息
            handler.sendEmptyMessage(1);//发送消息
    }
}


注释很详细,不解释 了。运行程序,结果如下:


这样子,就会一直循环下去,轮流打印出主线程和子线程。




Android主线程、子线程通信(Thread+handler)

Android是基于Java的,所以也分主线程,子线程!
主线程:实现业务逻辑、UI绘制更新、各子线程串连,类似于将军;
子线程:完成耗时(联网取数据、SD卡数据加载、后台长时间运行)操作,类似于小兵;

一、子线程向主线程发消息(Thread+handler):


1、主线程中定义Handler:

Handler mHandler = new Handler(){  
  
    @Override  
    public void handleMessage(Message msg) {  
        super.handleMessage(msg);  
        switch (msg.what) {  
        case 0:  
            //do something,refresh UI;  
            break;  
        default:  
            break;  
        }  
    }  
      
};

    
2、子线程处理完耗时操作之后发消息给主线程,更新UI:

mHandler.sendEmptyMessage(0);  

这样在子线程与主线程任务分工的条件下完成了消息交互;

二、主线程向子线程发送消息(Thread+handler):

主线程碰到耗时操作要子线程完成,此时发通知给子线程,操作步骤如下:

1、子线程中定义Handler,Handler定义在哪个线程中,就跟那个线程绑定,在线程中绑定Handler需要调用Looper.prepare();方法,主线程中不调用是因为主线程默认帮你调用了;

public class LoopThread implements Runnable {  
  
    public Handler mHandler = null;  
  
    @Override  
    public void run() {  
        Looper.prepare();  
        mHandler = new Handler() {  
            public void handleMessage(Message msg) {  
                String result = NetUtil.getJsonContent("北京");  
                //完成了获取北京天气的操作;  
                Log.i("test", "handler"+result);  
            }  
        };  
        Looper.loop();  
    }  
  
}



其中Looper.prepare();和Looper.loop();维护了一个消息队列,等待消息注入并在子线程中执行;

2、主线程中这样调用:


lThread.mHandler.sendEmptyMessage(0);  

主线程向子线程发消息,让子线程执行指定的操作,在Android中还有一种方法,即:HandlerThread,看下面的例子:

HandlerThread handlerThread = new HandlerThread("jerome");  
handlerThread.start();  
  
/** 
 * 这里要将HandlerThread创建的looper传递给threadHandler,即完成绑定; 
 */  
threadHandler = new Handler(handlerThread.getLooper()) {  
  
    @Override  
    public void handleMessage(Message msg) {  
        super.handleMessage(msg);  
        switch (msg.what) {  
        case 0:  
这儿可以做耗时的操作;  
            Log.i("jerome", "hello,I am sub thread");  
            break;  
        default:  
            break;  
        }  
    }  
};


在Android开发中,有时我们可能会遇到一个ListView中出现不同样式的item,那么我们如何处理不同的样式呢?本文分享两个实例。

还是先看效果图吧


我们再使用listview时,大多时候listview的item大多时候都是一种样式,在很多app中也很常见,但有时候根据需求,可能数据的数量不一样,同个类型的数据显示的位置不同,亦或者有的item需要图片,有的不需要,但是这些又必须在同一个listview中显示,这时我们就需要在listview中显示多种样式的item,首先我们需要考虑的是如何将不同数量的数据装载到ArrayList<~>中呢,先看看下面的listViewItem,。

package com.example.keranbin.myapplication;
import java.util.HashMap;
import java.util.Map;
public class lIstViewItem
{
    //用于区分listview显示的不同item,告诉适配器我这是什么类型,listview适配器根据type决定怎么显示
    public int type;
    //将要显示的数据用HashMap包装好
    public HashMap map ;
    
    public lIstViewItem(int type, HashMap map)
    {
        this.type = type;
        this.map = map;
    }
}


我们通过自定义一个listItem,即可将所有不同类型,不同数量的数据先组装成统一类型listItem即可,然后用arrayList.add(listitem)即可。

/**
     * 这里我们用三种不同的样式进行测试
     **/
    private ArrayList getDatas() {
        viewItemsArraylists = new ArrayList();
        viewItemsArraylists.add(new lIstViewItem(2, getHashMapThreeType("汪星人", "汪星人喜欢吃骨头", "2015-10-18")));
        viewItemsArraylists.add(new lIstViewItem(1, getHashMapSecondType("喵星人", "喵星喜欢吃鱼")));
        viewItemsArraylists.add(new lIstViewItem(0, getHashMapFirstType("猴子")));
        viewItemsArraylists.add(new lIstViewItem(0, getHashMapFirstType("老虎")));
        viewItemsArraylists.add(new lIstViewItem(1, getHashMapSecondType("老母鸡", "老母鸡喜欢吃虫子")));
        return viewItemsArraylists;
    }
    
    //第一种样式,只传输一个数据
    private HashMap getHashMapFirstType(String firstTheme) {
        HashMap hashMap = new HashMap();
        hashMap.put("Theme", firstTheme);
        return hashMap;
    }
    //第二种样式,传输两个数据
    private HashMap getHashMapSecondType(String secondTheme, String secondContent) {
        HashMap hashMap = new HashMap();
        hashMap.put("Theme", secondTheme);
        hashMap.put("Content", secondContent);
        return hashMap;
    }
    //第三种样式,传输三个数据
    private HashMap getHashMapThreeType(String threeTheme, String threeContent, String date) {
        HashMap hashMap = new HashMap();
        hashMap.put("Theme", threeTheme);
        hashMap.put("Content", threeContent);
        hashMap.put("Date", date);
        return hashMap;
    }

    
剩下的就是listViewAdapter的事情啦,和显示一种样式的listViewAdapter不同的一点是我们重写实现父类baseAdapter的两个方法。

//返回当前布局的样式type
    @Override
    public int getItemViewType(int position) {
        return listDatas.get(position).type;
    }
    //返回你有多少个不同的布局
    @Override
    public int getViewTypeCount() {
        return 3;
    }

    
然后在getView中根据需要进行判断决定显示那种样式即可

package com.example.keranbin.myapplication;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
/**
 * Created by keranbin on 2015/10/13.
 */
public class ListViewAdapter extends BaseAdapter {
    private LayoutInflater mLayoutInflater;
    private Context context;
    private ArrayList listDatas;
    public ListViewAdapter(Context context, ArrayList listDatas) {
        this.listDatas = listDatas;
        mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
    //返回当前布局的样式type
    @Override
    public int getItemViewType(int position) {
        return listDatas.get(position).type;
    }
    //返回你有多少个不同的布局
    @Override
    public int getViewTypeCount() {
        return 3;
    }
    @Override
    public int getCount() {
        return listDatas.size();
    }
    @Override
    public Object getItem(int position) {
        return listDatas.get(position);
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        lIstViewItem listItem = listDatas.get(position);
        int Type = getItemViewType(position);
        ViewHolderfirstType viewHolderfirstType = null;
        ViewHoldersecondType viewHoldersecondType = null;
        ViewHolderThreeType viewHolderThreeType = null;
        if (convertView == null) {
            switch (Type) {
                case 0:
                    viewHolderfirstType = new ViewHolderfirstType();
                    convertView = mLayoutInflater.inflate(R.layout.activity_first_type_item, null);
                    viewHolderfirstType.tv_first_theme= (TextView) convertView.findViewById(R.id.tv_first_theme);
                    viewHolderfirstType.tv_first_theme.setText(listItem.map.get("Theme").toString());
                    convertView.setTag(viewHolderfirstType);
                    break;
                case 1:
                    viewHoldersecondType = new ViewHoldersecondType();
                    convertView = mLayoutInflater.inflate(R.layout.activity_second_type_item, null);
                    viewHoldersecondType.tv_second_content = (TextView) convertView.findViewById(R.id.tv_second_content);
                    viewHoldersecondType.btn_second_theme = (Button) convertView.findViewById(R.id.btn_second_theme);
                    viewHoldersecondType.tv_second_content.setText(listItem.map.get("Theme").toString());
                    viewHoldersecondType.btn_second_theme.setText(listItem.map.get("Content").toString());
                    convertView.setTag(viewHoldersecondType);
                    break;
                case 2:
                    viewHolderThreeType = new ViewHolderThreeType();
                    convertView = mLayoutInflater.inflate(R.layout.activity_three_type_item, null);
                    viewHolderThreeType.tv_three_content = (TextView) convertView.findViewById(R.id.tv_three_content);
                    viewHolderThreeType.et_three_theme= (EditText) convertView.findViewById(R.id.et_three_theme);
                    viewHolderThreeType.tv_three_time= (TextView) convertView.findViewById(R.id.tv_three_time);
                    viewHolderThreeType.et_three_theme.setText(listItem.map.get("Theme").toString());
                    viewHolderThreeType.tv_three_content.setText(listItem.map.get("Content").toString());
                    viewHolderThreeType.tv_three_time.setText(listItem.map.get("Date").toString());
                    convertView.setTag(viewHolderThreeType);
                    break;
            }
        }else{
            switch (Type){
                case 0:
                    viewHolderfirstType= (ViewHolderfirstType) convertView.getTag();
                    viewHolderfirstType.tv_first_theme.setText(listItem.map.get("Theme").toString());
                    break;
                case 1:
                    viewHoldersecondType= (ViewHoldersecondType) convertView.getTag();
                    viewHoldersecondType.tv_second_content = (TextView) convertView.findViewById(R.id.tv_second_content);
                    viewHoldersecondType.btn_second_theme = (Button) convertView.findViewById(R.id.btn_second_theme);
                    viewHoldersecondType.tv_second_content.setText(listItem.map.get("Theme").toString());
                    viewHoldersecondType.btn_second_theme.setText(listItem.map.get("Content").toString());
                    break;
                case 2:
                    viewHolderThreeType= (ViewHolderThreeType) convertView.getTag();
                    viewHolderThreeType.tv_three_content = (TextView) convertView.findViewById(R.id.tv_three_content);
                    viewHolderThreeType.et_three_theme= (EditText) convertView.findViewById(R.id.et_three_theme);
                    viewHolderThreeType.tv_three_time= (TextView) convertView.findViewById(R.id.tv_three_time);
                    viewHolderThreeType.et_three_theme.setText(listItem.map.get("Theme").toString());
                    viewHolderThreeType.tv_three_content.setText(listItem.map.get("Content").toString());
                    viewHolderThreeType.tv_three_time.setText(listItem.map.get("Date").toString());
                    break;
            }
        }
        return convertView;
    }
    class ViewHolderfirstType {
        TextView tv_first_theme;
    }
    class ViewHoldersecondType {
        TextView tv_second_content;
        Button btn_second_theme;
    }
    class ViewHolderThreeType {
        EditText et_three_theme;
        TextView tv_three_content;
        TextView tv_three_time;
    }
}


第一种样式页面组件主要是一个TextView.

                


第二种样式页面组件主要是一个TextView和一个button.

                        


第三种样式页面组件主要是两个TextView和一个EditText.

                                


activity_main.xml文件非常简单,就一个listView。

    


下面是MainActivity的代码

package com.example.keranbin.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.HashMap;
public class MainActivity extends Activity {
    private ListView listView;                               //页面listview
    private ListViewAdapter listViewAdapter;                 //listview适配器
    private ArrayList viewItemsArraylists;     //Arraylist主要装载的是传给适配器的数据集合
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化页面组件及一些数据
        initView();
        //为listview设置适配器
        ListViewAdapter listViewAdapter = new ListViewAdapter(MainActivity.this, getDatas());
        listView.setAdapter(listViewAdapter);
    }
    //初始化页面组件及一些数据
    private void initView() {
        listView = (ListView) this.findViewById(R.id.listView);
        listViewAdapter = new ListViewAdapter(MainActivity.this, getDatas());
    }
    /**
     * 这里我们用三种不同的样式进行测试
     **/
    private ArrayList getDatas() {
        viewItemsArraylists = new ArrayList();
        viewItemsArraylists.add(new lIstViewItem(2, getHashMapThreeType("汪星人", "汪星人喜欢吃骨头", "2015-10-18")));
        viewItemsArraylists.add(new lIstViewItem(1, getHashMapSecondType("喵星人", "喵星喜欢吃鱼")));
        viewItemsArraylists.add(new lIstViewItem(0, getHashMapFirstType("猴子")));
        viewItemsArraylists.add(new lIstViewItem(0, getHashMapFirstType("老虎")));
        viewItemsArraylists.add(new lIstViewItem(1, getHashMapSecondType("老母鸡", "老母鸡喜欢吃虫子")));
        return viewItemsArraylists;
    }
    //第一种样式,只传输一个数据
    private HashMap getHashMapFirstType(String firstTheme) {
        HashMap hashMap = new HashMap();
        hashMap.put("Theme", firstTheme);
        return hashMap;
    }
    //第二种样式,传输两个数据
    private HashMap getHashMapSecondType(String secondTheme, String secondContent) {
        HashMap hashMap = new HashMap();
        hashMap.put("Theme", secondTheme);
        hashMap.put("Content", secondContent);
        return hashMap;
    }
    //第三种样式,传输三个数据
    private HashMap getHashMapThreeType(String threeTheme, String threeContent, String date) {
        HashMap hashMap = new HashMap();
        hashMap.put("Theme", threeTheme);
        hashMap.put("Content", threeContent);
        hashMap.put("Date", date);
        return hashMap;
    }
}

Android ListView存在多个item样式的处理方法


在项目开发的时候,相信大家可能会遇到一个ListView中出现多个不同的布局,遇到这个问题我的大致思路就是创建多个viewholder,在getViewType的时候设置不同位置的item用不同的viewholder,好了不废话那么多直接上代码:

package com.sunny.youdao;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class MyAdapter extends BaseAdapter {
    private Context mContext;
    private LinearLayout linearLayout = null;
    private LayoutInflater inflater;
    private List list = new ArrayList();
    private TextView tex;
    private final int VIEW_TYPE = 3;
    private final int TYPE_1 = 0;
    private final int TYPE_2 = 1;
    private final int TYPE_3 = 2;
    public MyAdapter(Context context, List list) {
        // TODO Auto-generated constructor stub
        this.mContext = context;
        this.list = list;
        inflater = LayoutInflater.from(mContext);
    }
    @Override
    public int getCount() {
        // TODO 自动生成的方法存根
        return list.size();
    }
    @Override
    public Object getItem(int position) {
        // TODO 自动生成的方法存根
        return list.get(position);
    }
    @Override
    public long getItemId(int position) {
        // TODO 自动生成的方法存根
        return position;
    }
    
    //每个convert view都会调用此方法,获得当前所需要的view样式
    @Override
    public int getItemViewType(int position) {
        // TODO Auto-generated method stub
        int viewtype = position%6;
        if(viewtype == 0)
        return TYPE_1;
        else if(viewtype < 3)
            return TYPE_2;
        else if(viewtype < 6)
            return TYPE_3;
        else
            return TYPE_1;
    }
    
    //返回样式的数量
    @Override
    public int getViewTypeCount() {
        // TODO Auto-generated method stub
        return 3;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        viewHolder1 holder1 = null;
        viewHolder2 holder2 = null;
        viewHolder3 holder3 = null;
        int type = getItemViewType(position);
        // 无convertView,需要new出各个控件
        if (convertView == null) {
            Log.e("convertView = ", "###convertView为空###");
            // 按当前所需的样式,确定new的布局
            switch (type) {
            case TYPE_1:
                convertView = inflater.inflate(R.layout.listitem1, parent,false);
                holder1 = new viewHolder1();
                holder1.textView = (TextView) convertView.findViewById(R.id.textview1);
                holder1.checkBox = (CheckBox) convertView.findViewById(R.id.checkbox);
                Log.e("convertView = ", "布局样式一");
                convertView.setTag(holder1);
                break;
            case TYPE_2:
                convertView = inflater.inflate(R.layout.listitem2, parent,false);
                holder2 = new viewHolder2();
                holder2.textView = (TextView) convertView.findViewById(R.id.textview2);
                Log.e("convertView = ", "布局样式二");
                convertView.setTag(holder2);
                break;
            case TYPE_3:
                convertView = inflater.inflate(R.layout.listitem3, parent,false);
                holder3 = new viewHolder3();
                holder3.textView = (TextView) convertView.findViewById(R.id.textview3);
                holder3.imageView = (ImageView) convertView.findViewById(R.id.imageview);
                Log.e("convertView = ", "布局样式三");
                convertView.setTag(holder3);
                break;
            }
        } else {
            // 有convertView,按样式,取得不用的布局
            switch (type) {
            case TYPE_1:
                holder1 = (viewHolder1) convertView.getTag();
                Log.e("convertView= ", "布局样式一");
                break;
            case TYPE_2:
                holder2 = (viewHolder2) convertView.getTag();
                Log.e("convertView= ", "布局样式二");
                break;
            case TYPE_3:
                holder3 = (viewHolder3) convertView.getTag();
                Log.e("convertView= ", "布局样式三");
                break;
            }
        }
        // 设置资源
        switch (type) {
        case TYPE_1:
            holder1.textView.setText(Integer.toString(position));
            holder1.checkBox.setChecked(true);
            break;
        case TYPE_2:
            holder2.textView.setText(Integer.toString(position));
            break;
        case TYPE_3:
            holder3.textView.setText(Integer.toString(position));
            holder3.imageView.setBackgroundResource(R.drawable.icon);
            break;
        }
        return convertView;
    }
    
    // 各个布局的控件资源
    class viewHolder1 {
        CheckBox checkBox;
        TextView textView;
    }
    class viewHolder2 {
        TextView textView;
    }
    class viewHolder3 {
        ImageView imageView;
        TextView textView;
    }
}


关于关于Eclipse 和 IDEA 导入library库文件,本教程使用图文并茂来详情讲解,非常实用,做Android开发的同学可以参考一下。

关于Eclipse 和 IDEA 导入library库文件,我们以PullToRefresh(上拉刷新下拉加载)组件的library为例来具体讲解。

PullToRefresh下载地址:https://github.com/chrisbanes/Android-PullToRefresh


我们的目的就是把library文件夹导入到Eclipse或者IDEA中去


一、IDEA 导入library库文件步骤


1、首先我们要有一个项目,没有的就创建一个吧

2、右击项目名称点击Open Module Settings(F4)


3、可以看到这样的界面


接下来在中间部分 点击绿色的加号 导入Module


找到要导入的library类库的目录


点击OK 后,,新的界面选择 第一个选项 Create module from existing sources,然后下一步知道import操作完成


4、然后就可以看到这样的界面,中间界面 多了一个library文件夹


5、接着点击最右边界面的绿色加号按钮 选择第三个Module Dependency,注意中间部分要选择你要导入library库文件的目录,即此时在中间界面选中demo文件夹,在按绿色按钮添加


6、可以看到有library文件夹可以选择 选择OK就行了 然后OK 结束设置


7、这是就可以看到你的项目里多了一个library文件夹


打开library文件夹可以看到文件夹内容都在,


8、我们在主Activity中添加一个library 提供的类检查是否导入成功,不报错可导入成功



二、Eclipse 导入library库文件步骤


1、导入


2、选择 Android/Existing Android Code Into Workspace


3、选择library文件夹目录 ,记得选中 Copy projects into workspace


4、可以看到项目目录多了library


5、右键library 选择properties (在最下面)

点击is Library --》ok


6、然后右击要导入library库文件的的项目 选择properties 添加Add 选择要导入的library文件夹


7、然后使用library库文件提供的类检测是否导入正确 (注意项目和library库文件需要在同一个目录下,即同一个工作空间)



[!--infotagslink--]

相关文章

  • Android子控件超出父控件的范围显示出来方法

    下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
  • c#检测usb设备拨插类库USBClassLibrary分享

    这篇文章主要介绍了c#检测usb设备拨插类库USBClassLibrary的简单示例,需要的朋友可以参考下...2020-06-25
  • Android开发中findViewById()函数用法与简化

    findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20
  • Android模拟器上模拟来电和短信配置

    如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
  • 夜神android模拟器设置代理的方法

    夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
  • android自定义动态设置Button样式【很常用】

    为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
  • Android WebView加载html5页面实例教程

    如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
  • ant design中upload组件上传大文件,显示进度条进度的实例

    这篇文章主要介绍了ant design中upload组件上传大文件,显示进度条进度的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-29
  • 深入理解Android中View和ViewGroup

    深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
  • Android自定义WebView网络视频播放控件例子

    下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
  • Android用MemoryFile文件类读写进行性能优化

    java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
  • 解决ant Design中this.props.form.validateFields未执行的问题

    这篇文章主要介绍了解决ant Design中this.props.form.validateFields未执行的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-28
  • Android设置TextView竖着显示实例

    TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
  • android.os.BinderProxy cannot be cast to com解决办法

    本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20
  • Android 实现钉钉自动打卡功能

    这篇文章主要介绍了Android 实现钉钉自动打卡功能的步骤,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下...2021-03-15
  • Android 开发之布局细节对比:RTL模式

    下面我们来看一篇关于Android 开发之布局细节对比:RTL模式 ,希望这篇文章对各位同学会带来帮助,具体的细节如下介绍。 前言 讲真,好久没写博客了,2016都过了一半了,赶紧...2016-10-02
  • Android中使用SDcard进行文件的读取方法

    首先如果要在程序中使用sdcard进行存储,我们必须要在AndroidManifset.xml文件进行下面的权限设置: 在AndroidManifest.xml中加入访问SDCard的权限如下: <!--...2016-09-20
  • Android开发之PhoneGap打包及错误解决办法

    下面来给各位简单的介绍一下关于Android开发之PhoneGap打包及错误解决办法,希望碰到此类问题的同学可进入参考一下哦。 在我安装、配置好PhoneGap项目的所有依赖...2016-09-20
  • 用Intel HAXM给Android模拟器Emulator加速

    Android 模拟器 Emulator 速度真心不给力,, 现在我们来介绍使用 Intel HAXM 技术为 Android 模拟器加速,使模拟器运行度与真机比肩。 周末试玩了一下在Eclipse中使...2016-09-20
  • Android判断当前屏幕是全屏还是非全屏

    在安卓开发时我碰到一个问题就是需要实现全屏,但又需要我们来判断出用户是使用了全屏或非全屏了,下面我分别找了两段代码,大家可参考。 先来看一个android屏幕全屏实...2016-09-20