Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android版微信5.3安裝目錄分析及主界面高仿

android版微信5.3安裝目錄分析及主界面高仿

編輯:關於Android編程

一、安裝目錄分析 最近在做手機項目時,涉及很多本地文件管理方面的內容,比如用戶的頭像、下載的圖片、視頻等等,將這些文件緩存在本地,必須設計一個合理的組織方式,這樣才能便於管理和後面的擴展及維護。這期間先後看了微視和美拍的本地文件組織方式,基本屬於大家都在采用的方式,即一個大的cache文件夾,然後裡面是按照類別劃分的子文件夾,分別存放圖片、視頻等。隨後又看了一下微信的組織方式,覺得微信的組織方式有點意思。同時也產生了幾個疑問,到現在也沒鬧明白。 微信的安裝目錄位於Tencent文件夾內,該文件夾下面都是騰訊家的軟件,什麼手機qq、微信等應用的安裝目錄都在這裡。其中MicroMsg文件夾就是微信的文件夾了,在使用微信過程中產生的圖片、語音等緩存文件都分門別類的存在這裡面。因為微信允許多帳號切換登錄,所以不同帳號產生的圖片、語音等緩存文件是分別存放的,本人分析應該是帳號加密後的密文做為文件夾名。 \
如上圖所示為我的帳號文件夾,進入該文件夾後,如下圖所示: \
又是一堆文件夾,挨個點開看看吧,有些文件夾裡面信息量還是很大的,比如image2文件夾,這裡面存的是聊天過程中發送和接收的圖片;sns文件夾,裡面的文件都是沒有擴展名的,不過將其拷貝至電腦,然後追加".png"或者".jpg"擴展名,然後就可以將其打開了,個人分析sns文件夾內存儲的應該是用戶浏覽朋友圈時產生的圖片;voice2文件夾,該文件夾保存的為所有聊天過程產生的語音文件,不管是一對一聊還是群聊,所有的語音文件都在這裡。該語音文件為普通的amr文件,可以用播放器(比如暴風影音)播放,拷貝至電腦或者直接雙擊播放試試吧。上面提到的幾個文件夾實際還有子文件夾,需要逐級打開才行。以voice2文件夾為例,實際打開voice2文件夾後,將會看到子文件夾,進入子文件夾後還會看到一級子文件夾,再次點擊進入才是上面提到的amr語音文件。而子文件夾的命名規則表面上看很簡單,為00至ff的十六進制命名,也就是最多有256個子文件夾。當用戶收到一條語音文件後,該文件放在00至ff哪個子文件夾內,這肯定需要某種映射算法,該映射算法應該是在服務端執行,當然也有可能是在客戶端這邊執行,即客戶端收到語音文件後,通過該映射算法,計算出該文件應該放在哪個文件下。這就是本人的第一個疑惑,沒搞明白這個文件夾結構的設計機制。本人的另一個疑惑就是微信amr語音文件的命名規則,首先每一條語音文件文件名由30個字符組成,前三個字符為msg前綴,然後是一串由日期拼接的數字,格式為秒-時-分-月-日-年,但是隨後的14個字符就讓人迷糊了,個人分析可能是帳號加密的密文,但是接收自相同帳號的語音文件,這14個字符又有些不同,想來想去,始終沒想明白。針對上面兩條疑惑,期待哪位高人出現,指點一下,不勝感激。
二、微信主界面高仿 分析完微信的安裝目錄,下面來高仿一下微信主界面。本人對微信主界面比較有好感,主要是其界面設計的非常簡介、美觀,雖然其tab頁面從原來底部移至現在頂部,剛開始著實讓我適應了一段時間。現在網上已經有高人做了高仿微信界面工作,原文寫的很詳細,思路很清晰,並附了源碼供下載研究,但是本人對其所使用的第三方PagerSlidingTabStrip類耿耿於懷,該類主要是通過自繪的方式實現tab的滑動與顯示,總覺得這樣做不夠簡潔。這個類包含了近600行代碼,雖然靈活性非常好,因為是采用自繪方式,所以可以隨意修改參數,以實現不同效果。但是因為內部邏輯較為復雜,並且注釋很少,這樣非常不利於代碼維護。這樣一個簡單的功能,采用這麼重的實現方式,實在得不償失。於是本人嘗試在原工程基礎上重寫tab頁面切換方式,將原工程自繪方式改為調用android系統組件的方式實現。修改後,代碼更加簡潔,邏輯調用也更加容易理解,同時也方便擴展和維護。工程中標題欄部分代碼,以及所有圖片資源均為原工程內容,本人沒有做過改動,均由細心的原工程作者編寫及提供。 tab頁面切換主要包含二部分,第一部分是頁面顯示,即點擊標簽頁時,tab頁面文字部分要顯示點擊狀態,然後選中標簽頁時,文字要顯示選中狀態,其實就是將默認文字顏色變換兩次,一次為點擊顏色,一次為選中顏色;第二部分為頁面切換,頁面切換又可以分為手指左右滑動切換及點擊tab文字切換。將這個思路理清楚後,功能上就好實現了。由於功能比較簡單,所以這裡就不做過多說明了。下面將主要代碼貼出來,很多地方都有注釋,比較好理解。首先為布局代碼:


    
        
        
        
	        
	        
	        
	            
	        
	        
	            
	        
	        
	            
	    
	    
        
        
    
    
    
     
    
    
    
    

下面為主工程代碼:
package com.example.wechatsample;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

/**
 * 高仿微信主界面
 */
public class MainActivity extends FragmentActivity implements OnClickListener, OnPageChangeListener
{
	private TextView[] tabTextView = null;
	private ImageView tabBottomLine = null;
	
	private ViewPager viewPager = null;
	private List listFragments = null;
	private FragmentPagerAdapter fmPagerAdapter = null;
	
	private int tabWidth = 0;
	private int curTabIndex = VIEW_ID_CHAT;
	
	private static final int VIEW_ID_CHAT = 0;
	private static final int VIEW_ID_FOUND = 1;
	private static final int VIEW_ID_CONTACTS = 2;

	@Override
	protected void onCreate(Bundle savedInstanceState) 
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		setOverflowShowingAlways();
		
		// 初始化tab文字
		tabTextView = new TextView[3];
		tabTextView[VIEW_ID_CHAT] = (TextView)findViewById(R.id.chatTextView);
		tabTextView[VIEW_ID_FOUND] = (TextView)findViewById(R.id.foundTextView);
		tabTextView[VIEW_ID_CONTACTS] = (TextView)findViewById(R.id.contactsTextView);
		tabTextView[VIEW_ID_CHAT].setOnClickListener(this);
		tabTextView[VIEW_ID_FOUND].setOnClickListener(this);
		tabTextView[VIEW_ID_CONTACTS].setOnClickListener(this);
		
		// 初始化tab標識線
		tabBottomLine = (ImageView)findViewById(R.id.tabBottomLine);
		RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams)tabBottomLine.getLayoutParams();
		DisplayMetrics dm = getResources().getDisplayMetrics();
		lParams.width = dm.widthPixels / 3;
		tabBottomLine.setLayoutParams(lParams);
		tabWidth = lParams.width;
		
		// 初始化頁面
		listFragments = new ArrayList();
		listFragments.add(new ChatFragment());
		listFragments.add(new FoundFragment());
		listFragments.add(new ContactsFragment());
		
		viewPager = (ViewPager)findViewById(R.id.viewPager);
		fmPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager())
		{
			@Override
			public int getCount()
			{
				return listFragments.size();
			}
			
			@Override
			public Fragment getItem(int index)
			{
				return listFragments.get(index);
			}
		};
		viewPager.setAdapter(fmPagerAdapter);
		viewPager.setOnPageChangeListener(this);
		viewPager.setCurrentItem(VIEW_ID_CHAT);
		updateTabTextStatus(VIEW_ID_CHAT);
	}

	// 更新tab文字選中狀態
	private void updateTabTextStatus(int index)
	{
		for (TextView tv : tabTextView)
		{
			tv.setTextColor(Color.parseColor("#2c2c2c"));
		}
		
		tabTextView[index].setTextColor(Color.parseColor("#45c01a"));
	}
	
	// 切換tab選項
	private void changeTabItem(int index)
	{
		Animation animation = new TranslateAnimation(curTabIndex*tabWidth , index*tabWidth, 0, 0);
		curTabIndex = index;
		animation.setFillAfter(true);
		animation.setDuration(300);
		tabBottomLine.startAnimation(animation);
		animation.setAnimationListener(new Animation.AnimationListener()
		{
			@Override
			public void onAnimationStart(Animation animation)
			{
			}
			
			@Override
			public void onAnimationRepeat(Animation animation)
			{
			}
			
			@Override
			public void onAnimationEnd(Animation animation)
			{
				// 動畫結束,更新文字選中狀態
				updateTabTextStatus(curTabIndex);
			}
		});
	}
	
	@Override
	public void onPageSelected(int position)
	{
		// 左右滑動切換tab頁
		changeTabItem(position);
	}
	
	@Override
	public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
	{
		
	}
	
	@Override
	public void onPageScrollStateChanged(int state)
	{
		
	}
	
	@Override
	public void onClick(View v)
	{
		// 點擊切換tab頁
		switch (v.getId())
		{
		case R.id.chatTextView:
			tabTextView[VIEW_ID_CHAT].setTextColor(Color.parseColor("#8a8a8a"));
			viewPager.setCurrentItem(VIEW_ID_CHAT);
			break;
		case R.id.foundTextView:
			tabTextView[VIEW_ID_FOUND].setTextColor(Color.parseColor("#8a8a8a"));
			viewPager.setCurrentItem(VIEW_ID_FOUND);
			break;
		case R.id.contactsTextView:
			tabTextView[VIEW_ID_CONTACTS].setTextColor(Color.parseColor("#8a8a8a"));
			viewPager.setCurrentItem(VIEW_ID_CONTACTS);
			break;
		default:
			break;
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) 
	{
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onMenuOpened(int featureId, Menu menu) 
	{
		if (featureId == Window.FEATURE_ACTION_BAR && menu != null) 
		{
			if (menu.getClass().getSimpleName().equals("MenuBuilder")) 
			{
				try 
				{
					Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
					m.setAccessible(true);
					m.invoke(menu, true);
				}
				catch (Exception e) 
				{
				}
			}
		}
		
		return super.onMenuOpened(featureId, menu);
	}

	private void setOverflowShowingAlways() 
	{
		try 
		{
			ViewConfiguration config = ViewConfiguration.get(this);
			Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
			menuKeyField.setAccessible(true);
			menuKeyField.setBoolean(config, false);
		} 
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
}
工程運行後的效果圖如下:
完整工程下載鏈接:http://download.csdn.net/detail/u013085897/7843389

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved