1.在目录packages/apps/Launcher3/res/drawable-hdpi下添加图片资源,这里的图片资源就是不同颜色的图片,每种颜色分为小尺寸一张,大尺寸一张,小尺寸图片做进行点击选择的imageview,大尺寸图片用于填充整个文件夹的颜色,比如:

packages/apps/Launcher3/res/drawable-hdpi/s1.png

packages/apps/Launcher3/res/drawable-hdpi/l1.png


2.在packages/apps/Launcher3/res/layout/user_folder.xml文件中添加可以进行文件夹颜色选择的布局,如下:

<!-- 把添加那几张有颜色的图片资源全部都放到folder_header这个线性布局中,并且宽度都设置为0,weight都设置为1 -->
	<LinearLayout 
	    android:id="@+id/folder_header"
	    android:layout_width="match_parent"
	    android:layout_height="20dp"
	    android:orientation="horizontal">
	    
	    <ImageView 
	        android:id="@+id/imagecolor1"
	        andorid:layout_marginTop="5dp"
	        android:layout_width="0dp"
	        android:layout_height="match_parent"
	        android:layout_weight="1"
	        android:src="@drawable/s1"/>
	    
	    <ImageView
	        android:id="@+id/imagecolor2"
	        android:layout_marginTop="5dp"
	        android:layout_width="0dp"
	        android:layout_height="match_parent"
	        android:layout_weight="1"
	        android:src="@drawable/s2"/>
	    
	    <ImageView
	        android:id="@+id/imagecolor2"
	        android:layout_marginTop="5dp"
	        android:layout_width="0dp"
	        android:layout_height="match_parent"
	        android:layout_weight="1"
	        android:src="@drawable/s3"/>
	    
	    <ImageView
	        android:id="@+id/imagecolor2"
	        android:layout_marginTop="5dp"
	        android:layout_width="0dp"
	        android:layout_height="match_parent"
	        android:layout_weight="1"
	        android:src="@drawable/s4"/>
	</LinearLayout>


3.该功能的添加涉及到了SQLite数据库,ContentResolver,ContentProvider的知识,需要精通android数据存储相关的知识

packages/apps/Launcher3/scr/com/android/launcher3/LauncherProvider.java这个类创建了SQLite数据库,并根据该数据库定义了ContentProvider。在该类的onCreate方法中创建数据库的相关代码中添加一条语句:"color TEXT DEFAULT '#FFFFFF',"+

如下所示,作用是给文件夹设置颜色属性,默认颜色为白色。

db.execSQL("CREATE TABLE favorites ("+
        		"_id INTEGER PRIMARY KEY,"+
        		"title TEXT,"+
        		"color TEXT DEFAULT '#FFFFFF',"+
        		"intent TEXT"+
        		"appWidgetId INTEGER NOT NULL DEFAULT -1"+
        		"icon BlOB"+
        		........+
        		");");



4.实现该功能最重要的类是packages/apps/Launcher3/scr/com/android/launcher3/Folder.java,这个类中实现了布局显示,操作效果,执行逻辑,修改的内容如下:

  • 需要导入的包如下:
import android.view.View;
import android.view.ViewGroup;
import android.graphics.Color;
import android.view.View.OnClickListener;
import android.net.Uri;
import android.content.ContentResolver;
import android.database.Cursor;
import com.android.launcher3.config.ProviderConfig;//提供一个访问权限
import android.content.ContentValues;
import android.os.SystemProperties;
  • 添加的变量有:
protected View folder_header;
private String mColor;
private long mId;
private ContentResolver cr;
private Uri CONTENT_URI;
private Context mContext;

  • 在构造方法Folder中添加一条语句,如下,用于获得context
this.mContext=context;

  • 从数据库中获取存储的相关颜色数据,对没有展开和展开的文件夹初始化,进行颜色设置
public void initColorFromDb(Context context){
    	mId=mInfo.id;
    	CONTENT_URI=Uri.parse("content://"+ProviderConfig.AUTHORITY+"/"+"favorites");
    	cr=context.getContentResolver();
    	coursor c=cr.query(CONTENT_URI,new String[]{"color",},"_id=?",new String[]{""+mInfo.id},null);
    	//public Cursor query(Uri uri,String[] projection,Stirng selection,String[] selectionArgs,String sortOrder)
    	//new String[]{"color",}是只有一个元素的字符串数组
    	if(c!=null){
    		c.moveToLast();
    		mColor=c.getString(c.getColumnIndex("color"));
    		Folder.this.setBackgroundColor(Color.parseColor(mColor));//这里设置的是文件夹展开后的背景颜色
    		if(mColor.equals("#FDD7D7")){
    			mFolderIcon.mPreviewBackground.setImageResource(R.drawable.l1);//这里设置的是文件夹没有展开时的颜色
    		}else if(mColor.equals("#FDF1D7")){
    			mFolderIcon.mPreviewBackground.setImageResource(R.drawable.l2);
    		}else if(mColor.equals("#FDA9D6")){
    			mFolderIcon.mPreviewBackground.setImageResource(R.drawable.l3);
    		}else if(mColor.equals("#AEFDB5")){
    			mFolderIcon.mPreviewBackground.setImageResource(R.drawable.l4);
    		}else{
    			mFolderIcon.mPreviewBackground.setImageResource(R.drawable.portal_ring_inner);
    		}
    	}else{
    		return;
    	}
    }

  • 给布局文件user_folder.xml中的四个可以进行点击的ImageView设置监听事件
folder_header=(View)findViewById(R.id.folder_header);//获取文件夹头部视图
    folder_header.setVisibility(View.VISIBLE);
    ImageListener imageListener=new ImageListener();//ImageListener继承了onClickListener
    findViewById(R.id.imagecolor1).setOnClickListener(imageListener);//对每个ImageView设置点击事件的监听
    findViewById(R.id.imagecolor2).setOnClickListener(imageListener);
    findViewById(R.id.imagecolor3).setOnClickListener(imageListener);
    findViewById(R.id.imagecolor4).setOnClickListener(imageListener);

  • 给文件名编辑框设置内边框
mFolderName.setPadding(0,0,0,8);

  • 在方法void bind(FolderInfo info)中调用方法initColorFromDb方法,如下
initColorFromDb(mContext);

  • 在方法onMeasure(int widthMeasureSpec,int heightMeasureSpec)中添加如下语句,用于动态设置控件folder_header的宽和高
folder_header.measure(contentAreaWidthSpec,folder_header.getLayoutParams().height);

  • 在Folder的整体布局中通过重写方法onLayout实现在ViewGroup中添加子View的布局,添加代码如下:
//onLayout方法是ViewGroup中子View的布局方法,用于放置子View的位置。放置子View很简单,只需要重写onLayout方法
    //然后获取子View的实例,调用子View的layout方法实现布局。一般要配合onMeasure测量方法一起使用
    @Override
    protected void onLayout(boolean changed,int left,int top,int right,int bottom){
    	super.onLayout(changed,left,top,right,bottom);
    	folder_header.layout(0,0,right,folder_header.getMeasuredHeight());//子View相对于父View的位置
    	
    	private class ImageListener implements View.OnClickListener{//为ImageView设置点击事件的实现逻辑
    		public void onClick(View v){
    			switch(v.getId()){
    			case R.id.imagecolor1:
    				Folder.this.setBackgroundColor(Color.parseColor("#FDD7D7"));
    				mFolderIcon.mPreviewBackground.setImageResource(R.drawable.l1);
    				ContentValues values1=new ContentValues();
    				values.put("color","#FDD7D7");
    				cr.update(CONTENT_URI,values1,"_id=?",new String[]{""+mId});
    			break;
    			
    			case R.id.imagecolor2:
    				Folder.this.setBackgroundColor(Color.parseColor("#FDF1D7"));
    				mFolderIcon.mPreviewBackground.setImageResource(R.drawable.l1);
    				ContentValues values1=new ContentValues();
    				values.put("color","#FDF1D7");
    				cr.update(CONTENT_URI,values1,"_id=?",new String[]{""+mId});
    			break;
    			
    			case R.id.imagecolor3:
    				Folder.this.setBackgroundColor(Color.parseColor("#FDA9D6"));
    				mFolderIcon.mPreviewBackground.setImageResource(R.drawable.l1);
    				ContentValues values1=new ContentValues();
    				values.put("color","#FDA9D6");
    				cr.update(CONTENT_URI,values1,"_id=?",new String[]{""+mId});
    			break;
    			
    			case R.id.imagecolor4:
    				Folder.this.setBackgroundColor(Color.parseColor("#AEFDB5"));
    				mFolderIcon.mPreviewBackground.setImageResource(R.drawable.l1);
    				ContentValues values1=new ContentValues();
    				values.put("color","#AEFDB5");
    				cr.update(CONTENT_URI,values1,"_id=?",new String[]{""+mId});
    			break;
    			}
    		}
    	}
    }

其他建表语句补充

public static final String CREATE_BOOK="create table book ( id integer primary key autoincrement,"
      "author text,"
      "price real,"
      "pages integer,"
      "name text)";

SQLite不像其他的数据库拥有众多繁杂的数据类型,它的数据类型很简单,integer表示整型,real表示浮点型,text表示文本类型,blob表示二进制类型