仿网易云音乐
https: //github.com /aa112901/remusic
RecyclerView多重itemType
public class Adapter extends RecyclerView .Adapter <RecyclerView .ViewHolder > {
final static int FIRST_ITEM = 0 ;
final static int ITEM = 1 ;
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if (viewType == FIRST_ITEM)
return new CommonItemViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.common_item
, viewGroup, false ));
else {
return new ListItemViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fragment_musci_common_item
, viewGroup, false ));
}
}
@Override
public int getItemViewType(int position) {
return position == FIRST_ITEM ? FIRST_ITEM : ITEM;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
model = mList.get(position - 1 );
if (holder instanceof ListItemViewHolder) {
((ListItemViewHolder) holder).mainTitle.setText(model.musicName.toString());
((ListItemViewHolder) holder).title.setText(model.artist.toString());
} else if (holder instanceof CommonItemViewHolder) {
((CommonItemViewHolder) holder).textView.setText("(共" + mList.size() + "首)" );
}
}
@Override
public int getItemCount() {
return (null != mList ? mList.size() + 1 : 0 );
}
public class CommonItemViewHolder extends RecyclerView .ViewHolder implements View .OnClickListener {
TextView textView;
ImageView select;
CommonItemViewHolder(View view) {
super (view);
this .textView = (TextView) view.findViewById(R.id.play_all_number);
this .select = (ImageView) view.findViewById(R.id.select);
}
}
public class ListItemViewHolder extends RecyclerView .ViewHolder implements View .OnClickListener {
ImageView moreOverflow;
TextView mainTitle, title;
TintImageView playState;
ListItemViewHolder(View view) {
super (view);
this .mainTitle = (TextView) view.findViewById(R.id.viewpager_list_toptext);
this .title = (TextView) view.findViewById(R.id.viewpager_list_bottom_text);
this .playState = (TintImageView) view.findViewById(R.id.play_state);
this .moreOverflow = (ImageView) view.findViewById(R.id.viewpager_list_button);
}
}
}
定时执行intent
final Intent shutdownIntent = new Intent(this , MediaService.class );
shutdownIntent.setAction(SHUTDOWN);
mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mShutdownIntent = PendingIntent.getService(this , 0 , shutdownIntent, 0 );
mAlarmManager.set (AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + IDLE_DELAY, mShutdownIntent);
电源管理
<uses-permission android:name ="android.permission.WAKE_LOCK" />
你可能还需要
<uses-permission android:name ="android.permission.DEVICE_POWER" />
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE)
wakeLock = pm.newWakeLock (PowerManager.SCREEN _BRIGHT_WAKE_LOCK
| PowerManager.ON _AFTER_RELEASE, "DPA" )
//一般在resume中保持常量
wakeLock.acquire ()
//pause后释放
wakeLock.release ()
具有过滤器的广播事件
final IntentFilter filter = new IntentFilter();
filter .addAction(SERVICECMD);
filter .addAction(TOGGLEPAUSE_ACTION);
filter .addAction(PAUSE_ACTION);
filter .addAction(STOP_ACTION);
filter .addAction(NEXT_ACTION);
filter .addAction(PREVIOUS_ACTION);
filter .addAction(PREVIOUS_FORCE_ACTION);
filter .addAction(REPEAT_ACTION);
filter .addAction(SHUFFLE_ACTION);
filter .addAction(TRY_GET_TRACKINFO);
filter .addAction(Intent.ACTION_SCREEN_OFF);
filter .addAction(LOCK_SCREEN);
filter .addAction(SEND_PROGRESS);
filter .addAction(SETQUEUE);
registerReceiver(mIntentReceiver, filter );
监听外部存储的安装和卸载事件
if (mUnmountReceiver == null ) {
mUnmountReceiver = new BroadcastReceiver() {
@Override
public void onReceive (final Context context, final Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
} else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
}
}
};
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_EJECT);
filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
filter.addDataScheme("file" );
registerReceiver(mUnmountReceiver, filter);
}
NotificationManager&AudioManager
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mAudioManager = (AudioManager) getSystemService(Context.AUDIO _SERVICE)
mMediaButtonReceiverComponent = new ComponentName(getPackageName(),
MediaButtonIntentReceiver.class .getName ())
mAudioManager.registerMediaButtonEventReceiver (mMediaButtonReceiverComponent)
播放音乐
mAudioManager = (AudioManager) getSystemService(Context.AUDIO _SERVICE)
//注册不知道什么东西,回头再看
mMediaButtonReceiverComponent = new ComponentName(getPackageName(),
MediaButtonIntentReceiver.class .getName ())
mAudioManager.registerMediaButtonEventReceiver (mMediaButtonReceiverComponent)
int status = mAudioManager.requestAudioFocus(mAudioFocusListener,
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (status != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
return ;
}
final Intent intent = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId());
intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName());
sendBroadcast(intent);
mPlayer = new MultiPlayer(this );
mPlayerHandler = new MusicPlayerHandler(this , mHandlerThread.getLooper());
mPlayer.setHandler(mPlayerHandler);
mPlayer.start();
获取音乐数据
//查询条件
private static final String[] PROJECTION = new String[]{
"audio._id AS _id" , MediaStore.Audio .Media .ARTIST , MediaStore.Audio .Media .ALBUM ,
MediaStore.Audio .Media .TITLE , MediaStore.Audio .Media .DATA ,
MediaStore.Audio .Media .MIME _TYPE, MediaStore.Audio .Media .ALBUM _ID,
MediaStore.Audio .Media .ARTIST _ID
}
//获取数据
MatrixCursor cursor = new MatrixCursor(PROJECTION)
cursor.addRow (new Object[]{info.songId , info.artist , info.albumName , info.musicName
, info.data , info.albumData , info.albumId , info.artistId })
cursor.moveToFirst ()
mCursor = cursor
cursor.close ()
mCursor.getString (mCursor.getColumnIndexOrThrow (AudioColumns.DATA ))
mCursor.getString (mCursor.getColumnIndexOrThrow (AudioColumns.ALBUM ))
mCursor.getString (mCursor.getColumnIndexOrThrow (AudioColumns.MIME _TYPE))
mCursor.getString (mCursor.getColumnIndexOrThrow (AudioColumns.TITLE ))
mCursor.getString (mCursor.getColumnIndexOrThrow (AudioColumns.ARTIST ))
mCursor.getLong (mCursor.getColumnIndexOrThrow (AudioColumns.ALBUM _ID))
mCursor.getLong (mCursor.getColumnIndexOrThrow (AudioColumns.ARTIST _ID))
子线程的Handler
private Thread mLrcThread = new Thread(new Runnable() {
@Override
public void run () {
Looper.prepare();
mLrcHandler = new Handler();
Looper.loop();
}
});
mLrcThread .start();
//也可以直接用HandlerThread
mHandlerThread = new HandlerThread("MusicPlayerHandler" ,
android.os .Process .THREAD _PRIORITY_BACKGROUND)
mHandlerThread.start ()
mPlayerHandler = new MusicPlayerHandler(this, mHandlerThread.getLooper ())
ObjectAnimator的反向动画
anim.start ();
anim.reverse();
设置Window的背景图
mContext.getWindow ().setBackgroundDrawableResource (R.color .background _material_light_1)
RecyclerViewItem动画
((SimpleItemAnimator) recyclerView.getItemAnimator ()).setSupportsChangeAnimations (false)
动态权限处理
if (CommonUtils.isLollipop () && ContextCompat.checkSelfPermission (mContext, Manifest.permission .READ _EXTERNAL_STORAGE) != PackageManager.PERMISSION _GRANTED) {
ActivityCompat.requestPermissions ((Activity) mContext,new String[]{Manifest.permission .READ _EXTERNAL_STORAGE}, 0 )
}
@Override
public void onRequestPermissionsResult (int requestCode, @NonNull String[] permissions, @NonNull int [] grantResults) {
super .onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 0 && grantResults[0 ] == PackageManager.PERMISSION_GRANTED) {
reloadAdapter();
}
}
@Override
public boolean onTouchEvent (MotionEvent evt) {
switch (evt.getAction()) {
case MotionEvent.ACTION_DOWN:
downPoint.x = evt.getX();
downPoint.y = evt.getY();
if (this .getChildCount() > 1 ) {
getParent().requestDisallowInterceptTouchEvent(true );
}
break ;
case MotionEvent.ACTION_MOVE:
if (this .getChildCount() > 1 ) {
getParent().requestDisallowInterceptTouchEvent(true );
}
break ;
case MotionEvent.ACTION_UP:
if (PointF.length(evt.getX() - downPoint.x, evt.getY()
- downPoint.y) < (float ) 5.0 ) {
onSingleTouch(this );
return true ;
}
break ;
}
return super .onTouchEvent(evt);
}
输入法管理器的使用
InputMethodManager mImm = (InputMethodManager) getSystemService(Context.INPUT _METHOD_SERVICE)
mImm.hideSoftInputFromWindow (mSearchView.getWindowToken (), 0 )
SearchView的使用
mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit (String query) {
return false ;
}
@Override
public boolean onQueryTextChange (String newText) {
return false ;
}
});
mSearchView.setQueryHint(getResources().getString(R.string.search_net_music));
mSearchView.setIconifiedByDefault(false );
mSearchView.setIconified(false );
<com .bilibili .magicasakura .widgets .TintToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/theme_color_primary"
android:minHeight="?attr/actionBarSize"
android:theme="@style/Theme.AppCompat"
app:popupTheme="@style/ThemeOverlay.AppCompat.Dark" >
<layout..
android:layout_height="?actionBarSize"
>
</>
Toolbar toolbar = (Toolbar) findViewById(R.id .toolbar )
toolbar.setPadding (0 , CommonUtils.getStatusHeight (this), 0 , 0 )
//需要设置为noActionBar
setSupportActionBar(toolbar)
getSupportActionBar().setDisplayHomeAsUpEnabled (true)
ActionBar ab = getSupportActionBar()
//home图标
ab.setHomeAsUpIndicator (R.drawable .ic _menu)
ab.setTitle ("" )
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:app ="http://schemas.android.com/apk/res-auto" >
<item
android:id ="@+id/menu_search"
android:orderInCategory ="1"
android:title ="@string/search"
app:actionViewClass ="android.support.v7.widget.SearchView"
app:showAsAction ="ifRoom|collapseActionView" />
</menu >
@Override
public boolean onCreateOptionsMenu (final Menu menu) {
getMenuInflater().inflate(R.menu.menu_search, menu);
mSearchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.menu_search));
MenuItemCompat.setOnActionExpandListener(menu.findItem(R.id.menu_search),
new MenuItemCompat.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand (MenuItem item) {
return true ;
}
@Override
public boolean onMenuItemActionCollapse (MenuItem item) {
return false ;
}
});
menu.findItem(R.id.menu_search).expandActionView();
return super .onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected (final MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true ;
default :
break ;
}
return super .onOptionsItemSelected(item);
}
舒服的AsyncTask使用方法
new AsyncTask<Boolean, Void, Boolean>() {
@Override
protected Boolean doInBackground (Boolean... params) {
SystemClock.sleep(3000 );
return true ;
}
@Override
protected void onPostExecute (Boolean load) {
super .onPostExecute(load);
}
}
}.execute();
自定义边界的位图
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android ="http://schemas.android.com/apk/res/android"
android:shape ="rectangle" >
<solid android:color ="@color/white_text" />
<stroke
android:color ="@color/test_color"
android:width ="1px" >
</stroke >
</shape >
帧动画 实现进度条效果
< animation-list android:oneshot= "false"
xmlns:android= "http://schemas.android.com/apk/res/android" >
< item android:duration = "133" android:drawable= "@drawable/loading1" / >
< item android:duration = "133" android:drawable= "@drawable/loading2" / >
< item android:duration = "133" android:drawable= "@drawable/loading3" / >
< item android:duration = "133" android:drawable= "@drawable/loading4" / >
< item android:duration = "133" android:drawable= "@drawable/loading3" / >
< item android:duration = "133" android:drawable= "@drawable/loading2" / >
< /animation-list >
AnimationDrawable animationDrawable = (AnimationDrawable) getResources().getDrawable (
R.drawable .list _loading)
barmusic.setBackground (animationDrawable)
animationDrawable.start ()
以Dialog做引导图
public class SplashScreen {
public final static int SLIDE_LEFT = 1 ;
public final static int SLIDE_UP = 2 ;
public final static int FADE_OUT = 3 ;
private Dialog splashDialog;
private Activity activity;
public SplashScreen (Activity activity) {
this .activity = activity;
}
/**
* @param animation 消失时的动画效果,取值可以是:SplashScreen.SLIDE_LEFT, SplashScreen.SLIDE_UP, SplashScreen.FADE
*/
public void show (final int imageResource, final int animation) {
Runnable runnable = new Runnable() {
public void run () {
DisplayMetrics metrics = new DisplayMetrics();
LinearLayout root = new LinearLayout(activity);
root.setMinimumHeight(metrics.heightPixels);
root.setMinimumWidth(metrics.widthPixels);
root.setOrientation(LinearLayout.VERTICAL);
root.setBackgroundColor(Color.BLACK);
root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, 0.0 F));
root.setBackgroundResource(imageResource);
splashDialog = new Dialog(activity, android.R.style.Theme_Translucent_NoTitleBar);
if ((activity.getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN)
== WindowManager.LayoutParams.FLAG_FULLSCREEN) {
splashDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
Window window = splashDialog.getWindow();
switch (animation) {
case SLIDE_LEFT:
window.setWindowAnimations(R.style.dialog_anim_slide_left);
break ;
case SLIDE_UP:
window.setWindowAnimations(R.style.dialog_anim_slide_up);
break ;
case FADE_OUT:
window.setWindowAnimations(R.style.dialog_anim_fade_out);
break ;
}
splashDialog.setContentView(root);
splashDialog.setCancelable(false );
splashDialog.show();
}
};
activity.runOnUiThread(runnable);
}
public void removeSplashScreen () {
if (splashDialog != null && splashDialog.isShowing()) {
splashDialog.dismiss();
splashDialog = null ;
}
}
}
//res/values/styles.xml
<resources xmlns:android ="http://schemas.android.com/tools" >
<style name ="dialog_anim_slide_left" mce_bogus ="1" parent ="android:Animation" >
<item name ="android :windowExitAnimation" >@anim/dialog_exit_slide_left</item>
</style >
<style name ="dialog_anim_slide_up" mce_bogus ="1" parent ="android:Animation" >
<item name ="android :windowExitAnimation" >@anim/dialog_exit_slide_up</item>
</style >
<style name ="dialog_anim_fade_out" mce_bogus ="1" parent ="android:Animation" >
<item name ="android :windowExitAnimation" >@anim/dialog_exit_fade_out</item>
</style >
</resources >
//res/anim/dialog_exit_slide_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android ="http://schemas.android.com/apk/res/android" >
<translate
android:duration ="3000"
android:fromXDelta ="0%"
android:fromYDelta ="0%"
android:interpolator ="@android:anim/accelerate_interpolator"
android:toXDelta ="-100%"
android:toYDelta ="0%" />
</set >
//res/anim/dialog_exit_fade_out.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android ="http://schemas.android.com/apk/res/android" >
<alpha
android:duration ="3000"
android:fromAlpha ="1.0"
android:interpolator ="@android:anim/accelerate_interpolator"
android:toAlpha ="0.0" />
</set >
//res/anim/dialog_exit_slide_up.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android ="http://schemas.android.com/apk/res/android" >
<translate
android:duration ="500"
android:fromXDelta ="0%"
android:fromYDelta ="0%"
android:interpolator ="@android:anim/accelerate_interpolator"
android:toXDelta ="0%"
android:toYDelta ="-100%" />
</set >
返回桌面
Intent intent = new Intent(Intent.ACTION _MAIN)
intent.addCategory (Intent.CATEGORY _HOME)
startActivity(intent)
@Override
public boolean onKeyDown (int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if ((System.currentTimeMillis() - time > 1000 )) {
Toast.makeText(this , "再按一次返回桌面" , Toast.LENGTH_SHORT).show();
time = System.currentTimeMillis();
} else {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
}
return true ;
} else {
return super .onKeyDown(keyCode, event);
}
}
某音乐播放器
Timber
https: //github.com /naman14/Timber
运用了谷歌的播放框架,看不懂,换一个
静态Fragment的使用
FrameLayout contentRoot = findViewById(R.id .content _root)
contentRoot.addView (LayoutInflater.from (this)
.inflate (R.layout .fragment _cast_mini_controller, null), params)
findViewById(R.id .castMiniController ).setOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this , ExpandedControllerActivity.class ))
}
})
//res/layout/fragment_cast_mini_controller.xml
<?xml version="1.0" encoding="utf-8"?>
<fragment
xmlns:android ="http://schemas.android.com/apk/res/android"
android:id ="@+id/castMiniController"
android:layout_width ="fill_parent"
android:layout_height ="wrap_content"
android:layout_alignParentBottom ="true"
android:layout_gravity ="bottom"
android:gravity ="bottom"
android:visibility ="gone"
class ="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment" />
动态权限的处理
public class Nammu {
private static final String TAG = Nammu.class.getSimpleName();
private static final String KEY_PREV_PERMISSIONS = "previous_permissions" ;
private static final String KEY_IGNORED_PERMISSIONS = "ignored_permissions" ;
private static Context context;
private static SharedPreferences sharedPreferences;
private static ArrayList<PermissionRequest> permissionRequests = new ArrayList<PermissionRequest>();
public static void init (Context context) {
sharedPreferences = context.getSharedPreferences("pl.tajchert.runtimepermissionhelper" , Context.MODE_PRIVATE);
Nammu.context = context;
}
/**
* Check that all given permissions have been granted by verifying that each entry in the
* given array is of the value {@link PackageManager#PERMISSION_GRANTED}.
*/
public static boolean verifyPermissions (int [] grantResults) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
return false ;
}
}
return true ;
}
/**
* Returns true if the Activity has access to given permissions.
*/
public static boolean hasPermission (Activity activity, String permission) {
return activity.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
}
/**
* Returns true if the Activity has access to a all given permission.
*/
public static boolean hasPermission (Activity activity, String[] permissions) {
for (String permission : permissions) {
if (activity.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
return false ;
}
}
return true ;
}
public static boolean shouldShowRequestPermissionRationale (Activity activity, String permissions) {
return activity.shouldShowRequestPermissionRationale(permissions);
}
public static void askForPermission (Activity activity, String permission, PermissionCallback permissionCallback) {
askForPermission(activity, new String[]{permission}, permissionCallback);
}
public static void askForPermission (Activity activity, String[] permissions, PermissionCallback permissionCallback) {
if (permissionCallback == null ) {
return ;
}
if (hasPermission(activity, permissions)) {
permissionCallback.permissionGranted();
return ;
}
PermissionRequest permissionRequest = new PermissionRequest(new ArrayList<String>(Arrays.asList(permissions)), permissionCallback);
permissionRequests.add(permissionRequest);
activity.requestPermissions(permissions, permissionRequest.getRequestCode());
}
public static void onRequestPermissionsResult (int requestCode, String[] permissions, int [] grantResults) {
PermissionRequest requestResult = new PermissionRequest(requestCode);
if (permissionRequests.contains(requestResult)) {
PermissionRequest permissionRequest = permissionRequests.get(permissionRequests.indexOf(requestResult));
if (verifyPermissions(grantResults)) {
permissionRequest.getPermissionCallback().permissionGranted();
} else {
permissionRequest.getPermissionCallback().permissionRefused();
}
permissionRequests.remove(requestResult);
}
refreshMonitoredList();
}
/**
* Get list of currently granted permissions, without saving it inside Nammu
*
* @return currently granted permissions
*/
public static ArrayList<String> getGrantedPermissions () {
if (context == null ) {
throw new RuntimeException("Must call init() earlier" );
}
ArrayList<String> permissions = new ArrayList<String>();
ArrayList<String> permissionsGranted = new ArrayList<String>();
permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
permissions.add(Manifest.permission.WRITE_CALENDAR);
permissions.add(Manifest.permission.READ_CALENDAR);
permissions.add(Manifest.permission.CAMERA);
permissions.add(Manifest.permission.WRITE_CONTACTS);
permissions.add(Manifest.permission.READ_CONTACTS);
permissions.add(Manifest.permission.GET_ACCOUNTS);
permissions.add(Manifest.permission.RECORD_AUDIO);
permissions.add(Manifest.permission.CALL_PHONE);
permissions.add(Manifest.permission.READ_PHONE_STATE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
permissions.add(Manifest.permission.READ_CALL_LOG);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
permissions.add(Manifest.permission.WRITE_CALL_LOG);
}
permissions.add(Manifest.permission.ADD_VOICEMAIL);
permissions.add(Manifest.permission.USE_SIP);
permissions.add(Manifest.permission.PROCESS_OUTGOING_CALLS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
permissions.add(Manifest.permission.BODY_SENSORS);
}
permissions.add(Manifest.permission.SEND_SMS);
permissions.add(Manifest.permission.READ_SMS);
permissions.add(Manifest.permission.RECEIVE_SMS);
permissions.add(Manifest.permission.RECEIVE_WAP_PUSH);
permissions.add(Manifest.permission.RECEIVE_MMS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
for (String permission : permissions) {
if (context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED) {
permissionsGranted.add(permission);
}
}
return permissionsGranted;
}
/**
* Refresh currently granted permission list, and save it for later comparing using @permissionCompare ()
*/
public static void refreshMonitoredList () {
ArrayList<String> permissions = getGrantedPermissions();
Set<String> set = new HashSet<String>();
for (String perm : permissions) {
set.add(perm);
}
sharedPreferences.edit().putStringSet(KEY_PREV_PERMISSIONS, set).apply();
}
/**
* Get list of previous Permissions, from last refreshMonitoredList() call and they may be outdated,
* use getGrantedPermissions() to get current
*/
public static ArrayList<String> getPreviousPermissions () {
ArrayList<String> prevPermissions = new ArrayList<String>();
prevPermissions.addAll(sharedPreferences.getStringSet(KEY_PREV_PERMISSIONS, new HashSet<String>()));
return prevPermissions;
}
public static ArrayList<String> getIgnoredPermissions () {
ArrayList<String> ignoredPermissions = new ArrayList<String>();
ignoredPermissions.addAll(sharedPreferences.getStringSet(KEY_IGNORED_PERMISSIONS, new HashSet<String>()));
return ignoredPermissions;
}
/**
* Lets see if we already ignore this permission
*/
public static boolean isIgnoredPermission (String permission) {
if (permission == null ) {
return false ;
}
return getIgnoredPermissions().contains(permission);
}
/**
* Use to ignore to particular Permission - even if user will deny or add it we won't receive a callback.
*
* @param permission Permission to ignore
*/
public static void ignorePermission (String permission) {
if (!isIgnoredPermission(permission)) {
ArrayList<String> ignoredPermissions = getIgnoredPermissions();
ignoredPermissions.add(permission);
Set<String> set = new HashSet<String>();
set.addAll(ignoredPermissions);
sharedPreferences.edit().putStringSet(KEY_IGNORED_PERMISSIONS, set).apply();
}
}
/**
* Used to trigger comparing process - @permissionListener will be called each time Permission was revoked, or added (but only once).
*
* @param permissionListener Callback that handles all permission changes
*/
public static void permissionCompare (PermissionListener permissionListener) {
if (context == null ) {
throw new RuntimeException("Before comparing permissions you need to call Nammu.init(context)" );
}
ArrayList<String> previouslyGranted = getPreviousPermissions();
ArrayList<String> currentPermissions = getGrantedPermissions();
ArrayList<String> ignoredPermissions = getIgnoredPermissions();
for (String permission : ignoredPermissions) {
if (previouslyGranted != null && !previouslyGranted.isEmpty()) {
if (previouslyGranted.contains(permission)) {
previouslyGranted.remove(permission);
}
}
if (currentPermissions != null && !currentPermissions.isEmpty()) {
if (currentPermissions.contains(permission)) {
currentPermissions.remove(permission);
}
}
}
for (String permission : currentPermissions) {
if (previouslyGranted.contains(permission)) {
previouslyGranted.remove(permission);
} else {
if (permissionListener != null ) {
permissionListener.permissionsChanged(permission);
permissionListener.permissionsGranted(permission);
}
}
}
if (previouslyGranted != null && !previouslyGranted.isEmpty()) {
for (String permission : previouslyGranted) {
if (permissionListener != null ) {
permissionListener.permissionsChanged(permission);
permissionListener.permissionsRemoved(permission);
}
}
}
refreshMonitoredList();
}
/**
* Not that needed method but if we override others it is good to keep same.
*/
public static boolean checkPermission (String permissionName) {
if (context == null ) {
throw new RuntimeException("Before comparing permissions you need to call Nammu.init(context)" );
}
return PackageManager.PERMISSION_GRANTED == context.checkSelfPermission(permissionName);
}
}
//使用前检查权限
if (Nammu.checkPermission (Manifest.permission .READ _EXTERNAL_STORAGE) && Nammu.checkPermission (Manifest.permission .WRITE _EXTERNAL_STORAGE)) {
loadEverything()
} else {
if (Nammu.shouldShowRequestPermissionRationale (this, Manifest.permission .READ _EXTERNAL_STORAGE)) {
Snackbar.make (panelLayout, "Timber will need to read external storage to display songs on your device." ,
Snackbar.LENGTH _INDEFINITE)
.setAction ("OK" , new View.OnClickListener () {
@Override
public void onClick(View view) {
Nammu.askForPermission (MainActivity.this , new String[]{Manifest.permission .READ _EXTERNAL_STORAGE, Manifest.permission .WRITE _EXTERNAL_STORAGE}
, permissionReadstorageCallback)
}
}).show ()
} else {
Nammu.askForPermission (this, new String[]{Manifest.permission .READ _EXTERNAL_STORAGE, Manifest.permission .WRITE _EXTERNAL_STORAGE}
, permissionReadstorageCallback)
}
}
//检查权限申请结果
@Override
public void onRequestPermissionsResult(
int requestCode, String[] permissions, int[] grantResults) {
Nammu.onRequestPermissionsResult (requestCode, permissions, grantResults)
}
DrawerLayout
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:app ="http://schemas.android.com/apk/res-auto"
android:id ="@+id/drawer_layout"
android:layout_width ="match_parent"
android:layout_height ="match_parent"
android:fitsSystemWindows ="true" > //自动填充
<include layout ="@layout/include_list_viewpager" />
<android.support.design.widget.NavigationView //navigationView 的使用
android:id ="@+id/nav_view"
android:layout_width ="wrap_content"
android:layout_height ="match_parent"
android:layout_gravity ="start" //设置方位
android:fitsSystemWindows ="true"
app:menu ="@menu/drawer_view" />
</android.support.v4.widget.DrawerLayout >
//res/menu/drawer_view.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android ="http://schemas.android.com/apk/res/android" >
<group
android:id ="@+id/group1"
android:checkableBehavior ="single" >
<item
android:id ="@+id/nav_library"
android:title ="@string/library" />
<item
android:id ="@+id/nav_playlists"
android:title ="@string/playlists" />
<item
android:id ="@+id/nav_folders"
android:title ="@string/folders" />
<item
android:id ="@+id/nav_queue"
android:title ="@string/playing_queue" />
<item
android:id ="@+id/nav_nowplaying"
android:checkable ="false"
android:title ="@string/now_playing" />
</group >
<group
android:id ="@+id/group2"
android:checkableBehavior ="none" >
<item
android:id ="@+id/nav_settings"
android:title ="@string/settings" />
<item
android:id ="@+id/nav_about"
android:title ="@string/about" />
<item
android:id ="@+id/nav_donate"
android:title ="Support development" />
</group >
</menu >
//res/layout/nav_header
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android ="http://schemas.android.com/apk/res/android"
android:layout_width ="match_parent"
android:layout_height ="208dp"
android:background ="?attr/colorPrimaryDark"
android:theme ="@style/ThemeOverlay.AppCompat.Dark"
android:orientation ="vertical"
android:gravity ="bottom" >
<ImageView
android:layout_width ="match_parent"
android:layout_height ="match_parent"
android:scaleType ="centerCrop"
android:id ="@+id/album_art" />
<LinearLayout
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
android:orientation ="vertical"
android:layout_gravity ="bottom"
android:gravity ="bottom" >
<TextView
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
android:id ="@+id/song_title"
android:textSize ="18sp"
android:textColor ="#ffffff"
android:singleLine ="true"
android:ellipsize ="end"
android:layout_marginLeft ="10dp"
android:layout_marginRight ="10dp"
android:textAppearance ="@style/TextAppearance.AppCompat.Body1" />
<TextView
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
android:id ="@+id/song_artist"
android:paddingTop ="2dp"
android:textSize ="15sp"
android:textColor ="#ffffff"
android:singleLine ="true"
android:ellipsize ="end"
android:layout_marginBottom ="10dp"
android:layout_marginLeft ="10dp"
android:layout_marginRight ="10dp"
android:textAppearance ="@style/TextAppearance.AppCompat.Body1" />
</LinearLayout >
<View
android:layout_width ="match_parent"
android:layout_height ="match_parent"
android:background ="?attr/selectableItemBackground" />
</FrameLayout >
mDrawerLayout = (DrawerLayout) findViewById(R.id .drawer _layout)
//navigationView的使用
navigationView = (NavigationView) findViewById(R.id .nav _view)
View header = navigationView.inflateHeaderView (R.layout .nav _header)
navigationView.setNavigationItemSelectedListener (
new NavigationView.OnNavigationItemSelectedListener () {
@Override
public boolean onNavigationItemSelected(final MenuItem menuItem) {
switch (menuItem.getItemId ()) {
case R.id .nav _library:
runnable = navigateLibrary
break
case R.id .nav _playlists:
runnable = navigatePlaylist
break
case R.id .nav _folders:
runnable = navigateFolder
break
case R.id .nav _nowplaying:
if (getCastSession() != null) {
startActivity(new Intent(MainActivity.this , ExpandedControlsActivity.class ))
} else {
NavigationUtils.navigateToNowplaying (MainActivity.this , false)
}
break
case R.id .nav _donate:
startActivity(new Intent(MainActivity.this , DonateActivity.class ))
break
}
return true
}
})
navigationView.getMenu ().findItem (R.id .nav _library).setIcon (R.drawable .library _music)
navigationView.getMenu ().findItem (R.id .nav _playlists).setIcon (R.drawable .playlist _play)
navigationView.getMenu ().findItem (R.id .nav _settings).setIcon (R.drawable .settings )
navigationView.getMenu ().findItem (R.id .nav _about).setIcon (R.drawable .information )
navigationView.getMenu ().findItem (R.id .nav _donate).setIcon (R.drawable .payment _black)
//需要设置打开menu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu (menu)
return true
}
//菜单选中的事件监听
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId ()) {
case android.R .id .home : {
if (isNavigatingMain()) {
mDrawerLayout.openDrawer (GravityCompat.START )
} else super.onBackPressed ()
return true
}
}
return super.onOptionsItemSelected (item)
}
//返回按键的处理
@Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen (GravityCompat.START )) {
mDrawerLayout.closeDrawer (GravityCompat.START )
} else {
super.onBackPressed ()
}
}
北京新闻
卡死了... .
Gallery的使用
<Gallery
xmlns:android ="http://schemas.android.com/apk/res/android"
android:id ="@+id/gallery"
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
android:layout_gravity ="center_vertical"
android:spacing ="1dip" />
private static class ImageAdapter extends BaseAdapter {
private LayoutInflater inflater;
private DisplayImageOptions options;
ImageAdapter(Context context) {
inflater = LayoutInflater.from(context);
}
@Override
public int getCount () {
return IMAGE_URLS.length;
}
@Override
public Object getItem (int position) {
return position;
}
@Override
public long getItemId (int position) {
return position;
}
@Override
public View getView (int position, View convertView, ViewGroup parent) {
ImageView imageView = (ImageView) convertView;
if (imageView == null ) {
imageView = (ImageView) inflater.inflate(R.layout.item_gallery_image, parent, false );
}
ImageLoader.getInstance().displayImage(IMAGE_URLS[position], imageView, options);
return imageView;
}
}
SparseArray
/**
* SparseArray替换HashMap,性能好于HashMap
*/
private SparseArray<T> datas;
datas.put(int , t);
解决PhotoView因延迟加载,测量错误导致的bug
PhotoView photoView = (PhotoView) findViewById(R.id.iv_photo);
final PhotoViewAttacher attacher = new PhotoViewAttacher(photoView);
Picasso.with(this )
.load(url)
.into(photoView, new Callback() {
@Override
public void onSuccess () {
attacher.update();
}
@Override
public void onError () {
}
});
public class NoScrollViewPager extends ViewPager {
/**
* 通常在代码中实例化的时候用该方法
* @param context
*/
public NoScrollViewPager (Context context) {
super (context);
}
/**
* 在布局文件中使用该类的时候,实例化该类用该构造方法,这个方法不能少,少的化会崩溃。
* @param context
* @param attrs
*/
public NoScrollViewPager (Context context, AttributeSet attrs) {
super (context, attrs);
}
/**
* 重写触摸事件,消费掉
* @param ev
* @return
*/
@Override
public boolean onTouchEvent (MotionEvent ev) {
return true ;
}
@Override
public boolean onInterceptTouchEvent (MotionEvent ev) {
return false ;
}
}
RadioGroup的使用
<RadioGroup
android:id="@+ id/rg_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable /bottom_tab_bg"
android:orientation="horizontal" >
<RadioButton
android:id="@+ id/rb_home"
android:drawableTop="@drawable /rb_home_drawable_selector"
android:gravity="center"
android:text="主页"
style="@style /bottom_tag_style"
/>
<RadioButton
android:id="@+ id/rb_newscenter"
android:drawableTop="@drawable /rb_newscenter_drawable_selector"
android:gravity="center"
android:text="新闻"
style="@style /bottom_tag_style"
/>
<RadioButton
android:id="@+ id/rb_smartservice"
android:drawableTop="@drawable /rb_smartservice_drawable_selector"
android:gravity="center"
android:text="商城"
style="@style /bottom_tag_style"
/>
<RadioButton
android:id="@+ id/rb_govaffair"
android:drawableTop="@drawable /rb_govaffair_drawable_selector"
android:gravity="center"
android:text="购物车"
style="@style /bottom_tag_style"
/>
<RadioButton
android:id="@+ id/rb_setting"
android:drawableTop="@drawable /rb_setting_drawable_selector"
android:gravity="center"
android:text="设置"
style="@style /bottom_tag_style"
/>
</RadioGroup>
//默认选中
rg_main.check (R.id .rb _home)
rg_main.setOnCheckedChangeListener(new MyOnCheckedChangeListener());
class MyOnCheckedChangeListener implements RadioGroup.OnCheckedChangeListener {
/**
* @param group RadioGroup
* @param checkedId 被选中的RadioButton的id
*/
@Override
public void onCheckedChanged (RadioGroup group, int checkedId) {
switch (checkedId){
case R.id.rb_home:
viewpager.setCurrentItem(0 ,false );
isEnableSlidingMenu(SlidingMenu.TOUCHMODE_NONE);
break ;
case R.id.rb_newscenter:
viewpager.setCurrentItem(1 ,false );
isEnableSlidingMenu(SlidingMenu.TOUCHMODE_FULLSCREEN);
break ;
case R.id.rb_smartservice:
viewpager.setCurrentItem(2 ,false );
isEnableSlidingMenu(SlidingMenu.TOUCHMODE_NONE);
break ;
case R.id.rb_govaffair:
viewpager.setCurrentItem(3 ,false );
isEnableSlidingMenu(SlidingMenu.TOUCHMODE_NONE);
break ;
case R.id.rb_setting:
viewpager.setCurrentItem(4 ,false );
isEnableSlidingMenu(SlidingMenu.TOUCHMODE_NONE);
break ;
}
}
}
//配合Fragment使用的逻辑
switch (frIndex) {
case ImageListFragment.INDEX :
tag = ImageListFragment.class .getSimpleName ()
fr = getSupportFragmentManager().findFragmentByTag (tag)
if (fr == null) {
fr = new ImageListFragment()
}
titleRes = R.string .ac _name_image_list
break
case ImageGridFragment.INDEX :
case ImagePagerFragment.INDEX :
case ImageGalleryFragment.INDEX :
}
getSupportFragmentManager().beginTransaction ().replace (android.R .id .content , fr, tag).commit ()
自定义崩溃收集
public class CrashHandler implements UncaughtExceptionHandler {
public static final String TAG = "CrashHandler" ;
private Thread.UncaughtExceptionHandler mDefaultHandler;
private static CrashHandler instance;
private Context mContext;
private Map<String, String> infos = new HashMap<String, String>();
private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss" );
/** 保证只有一个CrashHandler实例 */
private CrashHandler () {}
/** 获取CrashHandler实例 ,单例模式 */
public static CrashHandler getInstance () {
if (instance == null )
instance = new CrashHandler();
return instance;
}
/**
* 初始化
*/
public void init (Context context) {
mContext = context;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this );
}
/**
* 当UncaughtException发生时会转入该函数来处理
*/
@Override
public void uncaughtException (Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null ) {
mDefaultHandler.uncaughtException(thread, ex);
} else {
try {
Thread.sleep(3000 );
} catch (InterruptedException e) {
Log.e(TAG, "error : " , e);
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1 );
}
}
/**
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
*
* @param ex
* @return true:如果处理了该异常信息;否则返回false.
*/
private boolean handleException (Throwable ex) {
if (ex == null ) {
return false ;
}
collectDeviceInfo(mContext);
new Thread() {
@Override
public void run () {
Looper.prepare();
Toast.makeText(mContext, "北京新闻程序出现异常,即将退出." , Toast.LENGTH_SHORT).show();
Looper.loop();
}
}.start();
saveCatchInfo2File(ex);
return true ;
}
/**
* 收集设备参数信息
* @param ctx
*/
public void collectDeviceInfo (Context ctx) {
try {
PackageManager pm = ctx.getPackageManager();
PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
if (pi != null ) {
String versionName = pi.versionName == null ? "null" : pi.versionName;
String versionCode = pi.versionCode + "" ;
infos.put("versionName" , versionName);
infos.put("versionCode" , versionCode);
}
} catch (NameNotFoundException e) {
Log.e(TAG, "an error occured when collect package info" , e);
}
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true );
infos.put(field.getName(), field.get(null ).toString());
Log.d(TAG, field.getName() + " : " + field.get(null ));
} catch (Exception e) {
Log.e(TAG, "an error occured when collect crash info" , e);
}
}
}
/**
* 保存错误信息到文件中
*
* @param ex
* @return 返回文件名称,便于将文件传送到服务器
*/
private String saveCatchInfo2File (Throwable ex) {
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, String> entry : infos.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
sb.append(key + "=" + value + "\n" );
}
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
ex.printStackTrace(printWriter);
Throwable cause = ex.getCause();
while (cause != null ) {
cause.printStackTrace(printWriter);
cause = cause.getCause();
}
printWriter.close();
String result = writer.toString();
sb.append(result);
try {
long timestamp = System.currentTimeMillis();
String time = formatter.format(new Date());
String fileName = "crash-" + time + "-" + timestamp + ".log" ;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String path = Environment.getExternalStorageDirectory()+"/beijingnews/crash/" ;
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
FileOutputStream fos = new FileOutputStream(path + fileName);
fos.write(sb.toString().getBytes());
sendCrashLog2PM(path+fileName);
fos.close();
}
return fileName;
} catch (Exception e) {
Log.e(TAG, "an error occured while writing file..." , e);
}
return null ;
}
/**
* 将捕获的导致崩溃的错误信息发送给开发人员
*
* 目前只将log日志保存在sdcard 和输出到LogCat中,并未发送给后台。
*/
private void sendCrashLog2PM (String fileName){
if (!new File(fileName).exists()){
Toast.makeText(mContext, "日志文件不存在!" , Toast.LENGTH_SHORT).show();
return ;
}
FileInputStream fis = null ;
BufferedReader reader = null ;
String s = null ;
try {
fis = new FileInputStream(fileName);
reader = new BufferedReader(new InputStreamReader(fis, "GBK" ));
while (true ){
s = reader.readLine();
if (s == null ) break ;
Log.i("info" , s.toString());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
reader.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
在application中注册
public class BeijingNewsApplication extends Application {
/**
所有组件被创建之前执行
*/
@Override
public void onCreate () {
super .onCreate();
CrashHandler catchHandler = CrashHandler.getInstance();
catchHandler.init(getApplicationContext());
}
}
FragmentManger通过Tag获取Fragment
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm. beginTransaction();
ft . replace(R. id. fl_main_content,new ContentFragment(), MAIN_CONTENT_TAG);
ft . replace(R. id. fl_leftmenu, new LeftmenuFragment(), LEFTMENU_TAG);
ft . commit();
(LeftmenuFragment) getSupportFragmentManager(). findFragmentByTag(LEFTMENU_TAG);
github:
https: //github.com /jfeinstein10/SlidingMenu
//1. 继承
MainActivity extends SlidingFragmentActivity
//2. 设置侧滑布局
setBehindContentView(R.layout .activity _leftmenu)
//3. 设置侧滑布局的样式
//设置显示的模式:左侧菜单+主页,左侧菜单+主页面+右侧菜单;主页面+右侧菜单
slidingMenu.setMode (SlidingMenu.LEFT )
//设置滑动模式:滑动边缘,全屏滑动,不可以滑动
slidingMenu.setTouchModeAbove (SlidingMenu.TOUCHMODE _FULLSCREEN)
//设置占据的宽度
DisplayMetrics outmetrics = new DisplayMetrics()
getWindowManager().getDefaultDisplay ().getMetrics (outmetrics)
screeWidth = outmetrics.widthPixels
screeHeight = outmetrics.heightPixels
slidingMenu.setBehindOffset ((int) (screeWidth*0.625 ))
<RelativeLayout xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:tools ="http://schemas.android.com/tools"
android:layout_width ="match_parent"
android:layout_height ="match_parent"
tools:context ="com.atguigu.beijingnews.activity.GuideActivity" >
<android.support.v4.view.ViewPager
android:id ="@+id/viewpager"
android:layout_width ="match_parent"
android:layout_height ="match_parent" />
<RelativeLayout
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:layout_alignParentBottom ="true"
android:layout_centerHorizontal ="true"
android:layout_marginBottom ="40dp" >
//小圆点的位置的viewgroup
<LinearLayout
android:id ="@+id/ll_point_group"
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:orientation ="horizontal" />
//红色的小圆点指示器
<ImageView
android:id ="@+id/iv_red_point"
android:background ="@drawable/point_red"
android:layout_width ="10dp"
android:layout_height ="10dp" />
</RelativeLayout >
</RelativeLayout >
for (int i = 0 ; i < ids.length; i++) {
ImageView point = new ImageView(this );
point.setBackgroundResource(R.drawable.point_normal);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(widthdpi,widthdpi);
if (i !=0 ){
params .leftMargin = widthdpi;
}
point.setLayoutParams(params );
ll_point_group.addView(point);
}
iv_red_point.getViewTreeObserver().addOnGlobalLayoutListener(new MyOnGlobalLayoutListener());
class MyOnGlobalLayoutListener implements ViewTreeObserver .OnGlobalLayoutListener {
@Override
public void onGlobalLayout() {
iv_red_point.getViewTreeObserver()
.removeGlobalOnLayoutListener(MyOnGlobalLayoutListener.this );
leftmax = ll_point_group.getChildAt(1 ).getLeft() - ll_point_group.getChildAt(0 ).getLeft();
}
}
viewpager.addOnPageChangeListener(new MyOnPageChangeListener());
class MyOnPageChangeListener implements ViewPager.OnPageChangeListener {
/**
* 当页面回调了会回调这个方法
* @param position 当前滑动页面的位置
* @param positionOffset 页面滑动的百分比
* @param positionOffsetPixels 滑动的像数
*/
@Override
public void onPageScrolled (int position, float positionOffset, int positionOffsetPixels) {
int leftmargin = (int ) (position*leftmax + (positionOffset * leftmax));
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) iv_red_point.getLayoutParams();
params.leftMargin = leftmargin;
iv_red_point.setLayoutParams(params);
}
@Override
public void onPageSelected (int position) {
}
@Override
public void onPageScrollStateChanged (int state) {
}
}
高仿知乎专栏
https: //github.com /bxbxbai/ZhuanLan.git
SystemClock.sleep和Thread.sleep的区别
Thread.sleep()是java提供的函数。在调用该函数的过程中可能会发生InterruptedException异常。
SystemClock.sleep()是android提供的函数。在调用该函数的过程中不会发生InterruptedException异常,中断事件将要被延迟直到下一个中断事件。Use this function for delays if you do not useThread.interrupt(), as it will preserve the interrupted state of the thread.
ProgressBar常用设置
<ProgressBar
android:id ="@+id/bar_progressbar"
style="@style/FloatProgressBar"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginBottom="2dip"
android:layout_marginLeft="2dip"
android:layout_marginTop="2dip"
android:layout_toRightOf="@id/image_line"
android:indeterminate="false"
android:indeterminateOnly="false"
android:max="100"
android:progress="10" >
</ProgressBar>
<style name ="FloatProgressBar" parent="@android:style/Widget.ProgressBar.Horizontal" >
<item name ="android:indeterminateOnly" >false </item >
<item name ="android:progressDrawable" >@drawable/float_progressbar</item >
<item name ="android:minWidth" >14 dip</item >
<item name ="android:maxWidth" >14 dip</item >
<item name ="android:minHeight" >14 dip</item >
<item name ="android:maxHeight" >14 dip</item >
</style>
Thread的中断
thread = new Thread(new Runnable() {
@Override
public void run () {
while (!Thread.currentThread().isInterrupted()) {
SystemClock.sleep(250 );
i += 5 ;
FloatView.this .post(new Runnable() {
@Override
public void run () {
progressBar.setProgress(i);
Log.d("meee" ,getClass()+":\n" +"i:" +i);
}
});
if (i > 100 ) {
i = 0 ;
}
}
}
});
thread.start();
thread.interrupt();
自定义Behavior
public class AvatarImageBehavior extends CoordinatorLayout.Behavior<CircleImageView> {
private final static float MIN_AVATAR_PERCENTAGE_SIZE = 0.3 f;
private final static int EXTRA_FINAL_AVATAR_PADDING = 80 ;
private final static String TAG = "behavior" ;
private final Context mContext;
private float mAvatarMaxSize;
private float mFinalLeftAvatarPadding;
private float mStartPosition;
private int mStartXPosition;
private float mStartToolbarPosition;
private int mStartYPosition;
private int mFinalYPosition;
private int finalHeight;
private int mStartHeight;
private int mFinalXPosition;
public AvatarImageBehavior (Context context, AttributeSet attrs) {
mContext = context;
mAvatarMaxSize = mContext.getResources().getDimension(R.dimen.image_width);
mFinalLeftAvatarPadding = 100 ;
}
@Override
public boolean layoutDependsOn (CoordinatorLayout parent, CircleImageView child, View dependency) {
return dependency instanceof Toolbar;
}
@Override
public boolean onDependentViewChanged (CoordinatorLayout parent, CircleImageView child, View dependency) {
shouldInitProperties(child, dependency);
final int maxScrollDistance = (int ) (mStartToolbarPosition - getStatusBarHeight());
float expandedPercentageFactor = dependency.getY() / maxScrollDistance;
float distanceYToSubtract = ((mStartYPosition - mFinalYPosition)
* (1 f - expandedPercentageFactor)) + (child.getHeight()/2 );
float distanceXToSubtract = ((mStartXPosition - mFinalXPosition)
* (1 f - expandedPercentageFactor)) + (child.getWidth()/2 );
float heightToSubtract = (mStartHeight - finalHeight) * (1 f - expandedPercentageFactor);
child.setY(mStartYPosition - distanceYToSubtract);
child.setX(mStartXPosition - distanceXToSubtract);
int proportionalAvatarSize = (int ) (mAvatarMaxSize * (expandedPercentageFactor));
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
lp.width = (int ) (mStartHeight - heightToSubtract);
lp.height = (int ) (mStartHeight - heightToSubtract);
child.setLayoutParams(lp);
return true ;
}
private void shouldInitProperties (CircleImageView child, View dependency) {
if (mStartYPosition == 0 )
mStartYPosition = (int ) (child.getY() + (child.getHeight() / 2 ));
if (mFinalYPosition == 0 )
mFinalYPosition = dependency.getHeight() /2 ;
if (mStartHeight == 0 )
mStartHeight = child.getHeight();
if (finalHeight == 0 )
finalHeight = mContext.getResources().getDimensionPixelOffset(R.dimen.image_final_width);
if (mStartXPosition == 0 )
mStartXPosition = (int ) (child.getX() + (child.getWidth() / 2 ));
if (mFinalXPosition == 0 )
mFinalXPosition = mContext.getResources().getDimensionPixelOffset(R.dimen.abc_action_bar_content_inset_material) + (finalHeight / 2 );
if (mStartToolbarPosition == 0 )
mStartToolbarPosition = dependency.getY() + (dependency.getHeight()/2 );
}
public int getStatusBarHeight () {
int result = 0 ;
int resourceId = mContext.getResources().getIdentifier("status_bar_height" , "dimen" , "android" );
if (resourceId > 0 ) {
result = mContext.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
}
在photoView上添加view
添加权限,此乃高危权限
<uses-permission android:name ="android.permission.SYSTEM_ALERT_WINDOW" />
TextView view=new TextView(this)
view.setText ("你好啊" )
WindowManager wm = (WindowManager) getApplicationContext().getSystemService (Context.WINDOW _SERVICE)
WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams ()
wmParams.type = WindowManager.LayoutParams .TYPE _PHONE
wmParams.format = PixelFormat.RGBA _8888
wmParams.flags |= 8
wmParams.gravity = Gravity.RIGHT | Gravity.CENTER _VERTICAL
wmParams.x = 0
wmParams.y = 80
wmParams.width = ViewGroup.LayoutParams .WRAP _CONTENT
wmParams.height = ViewGroup.LayoutParams .WRAP _CONTENT
view.setOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View v) {
Toast.makeText (getApplicationContext(),"你好啊" ,Toast.LENGTH _SHORT).show ()
}
})
//添加到屏幕上后不能再修改view,否则抛异常
wm.addView (view, wmParams)
判断act是不是第一次启动,第一次添加Fragment
onCreate (savedInstanceState : Bundle ?) {
if (savedInstanceState == null) {
replaceToFlexboxLayoutFragment (fragmentManager )
}}
FragmentTyTag的使用
private fun replaceToFlexboxLayoutFragment (fragmentManager: FragmentManager) {
var fragment: FlexboxLayoutFragment? = fragmentManager.findFragmentByTag(FLEXBOXLAYOUT_FRAGMENT) as FlexboxLayoutFragment?
if (fragment == null ) {
fragment = FlexboxLayoutFragment.newInstance()
}
fragmentManager.beginTransaction()
.replace(R.id.container, fragment, FLEXBOXLAYOUT_FRAGMENT)
.commit()
}
使用Scanner类进行文本的读取
private String readFile (String fileName) {
AssetManager manager = getActivity().getAssets();
try {
Scanner scanner = new Scanner(manager.open(fileName));
StringBuilder builder = new StringBuilder();
while (scanner.hasNext()) {
builder.append(scanner.nextLine());
}
return builder.toString();
} catch (IOException e) {
e.printStackTrace();
}
return "" ;
}
public class ObservableScrollView extends NestedScrollView {
private List<OnScrollListener> listenerList = new ArrayList<>();
public ObservableScrollView (Context context) {
super (context);
}
public ObservableScrollView (Context context, AttributeSet attrs) {
super (context, attrs);
}
public ObservableScrollView (Context context, AttributeSet attrs, int defStyleAttr) {
super (context, attrs, defStyleAttr);
}
@Override
protected void onScrollChanged (int l, int t, int oldl, int oldt) {
super .onScrollChanged(l, t, oldl, oldt);
for (OnScrollListener listener : listenerList) {
listener.onScroll(t - oldt);
}
}
public void addOnScrollListener (OnScrollListener listener) {
listenerList.add(listener);
}
public interface OnScrollListener {
void onScroll(int distance);
}
}
WebView的封装
public class CommonWebView extends WebView {
public static final String ENCODING_UTF_8 = "UTF-8" ;
public static final String MIME_TYPE = "text/html" ;
public CommonWebView (Context context) {
super (context);
init();
}
public CommonWebView (Context context, AttributeSet attrs) {
super (context, attrs);
init();
}
public CommonWebView (Context context, AttributeSet attrs, int defStyleAttr) {
super (context, attrs, defStyleAttr);
init();
}
@TargetApi (Build.VERSION_CODES.LOLLIPOP)
public CommonWebView (Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super (context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init () {
if (isInEditMode()) {
return ;
}
WebSettings settings = getSettings();
settings.setJavaScriptEnabled(true );
settings.setBuiltInZoomControls(false );
settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
settings.setDomStorageEnabled(true );
settings.setDatabaseEnabled(true );
String cacheDir = getContext().getFilesDir().getAbsolutePath() + "web_cache" ;
settings.setAppCachePath(cacheDir);
settings.setAppCacheEnabled(true );
settings.setLoadsImagesAutomatically(true );
settings.setDefaultTextEncodingName(ENCODING_UTF_8);
settings.setBlockNetworkImage(false );
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
settings.setUseWideViewPort(true );
settings.setLoadWithOverviewMode(true );
setHorizontalScrollBarEnabled(false );
}
}
public class ZhuanLanWebViewClient extends WebViewClient {
private Activity mActivity;
public ZhuanLanWebViewClient (Activity activity) {
mActivity = activity;
}
@Override
public void onLoadResource (WebView view, String url) {
super .onLoadResource(view, url);
}
@Override
public boolean shouldOverrideUrlLoading (WebView view, String url) {
if (url != null && url.startsWith("orpheus" )) {
return true ;
}
if (url != null && url.startsWith("http" )) {
WebActivity.start(mActivity, url);
return true ;
}
return true ;
}
@Override
public WebResourceResponse shouldInterceptRequest (WebView view, String url) {
return super .shouldInterceptRequest(view, url);
}
@Override
public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request) {
return super .shouldInterceptRequest(view, request);
}
@Override
public void onPageStarted (WebView view, String url, Bitmap favicon) {
super .onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished (WebView view, String url) {
super .onPageFinished(view, url);
}
@Override
public void onReceivedError (WebView view, int errorCode, String description, String failingUrl) {
super .onReceivedError(view, errorCode, description, failingUrl);
}
}
mWebView.setWebViewClient(new ZhuanLanWebViewClient(getActivity()));
String content = String .format(readFile("template.txt" ), section);
mWebView.loadDataWithBaseURL(null , content, "text/html" , "UTF-8" , null );
mWebView.loadUrl("javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var style = document.createElement('style');" +
"style.type = 'text/css';" +
"style.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(style)" +
"})()" );
当Act打开时数据异常的处理
@Override
protected void onCreate (Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.coordinator_template);
post = getIntent().getParcelableExtra(StoryFragment.KEY_POST);
if (post == null ) {
finish();
return ;
}
}
自定义圆角背景图
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android ="http://schemas.android.com/apk/res/android" >
<item android:drawable ="@drawable/background_button" /> //一张9.图
<item android:id ="@+id/shape_background" >
<shape >
<solid android:color ="@color/feed_item_bg" /> //#fff
<corners android:radius ="@dimen/feed_item_corner_radius" /> //3dp
</shape >
</item >
</layer-list >
Context打开Act
final Intent intent = new Intent();
intent.setClass(context, PostListActivity.class);
intent.putExtra(KEY_USER, userEntity);
CommonExecutor.MAIN_HANDLER.postDelayed(new Runnable() {
@Override
public void run () {
context.startActivity(intent);
}
}, 420 );
菜单栏的使用
//res/menu/main.xml
<menu xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:app ="http://schemas.android.com/apk/res-auto" >
<item
android:id ="@+id/action_settings"
android:orderInCategory ="10"
app:showAsAction ="never"
android:title ="@string/action_settings" />
<item
android:id ="@+id/action_about"
android:orderInCategory ="100"
android:title ="@string/settings_others_about" />
</menu >
@Override
public boolean onCreateOptionsMenu (Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true ;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId ()){
case R.id .action _settings:
Toast.makeText (getApplicationContext(),"action_settings" ,Toast.LENGTH _SHORT).show ()
break
case R.id .action _about:
Toast.makeText (getApplicationContext(),"action_about" ,Toast.LENGTH _SHORT).show ()
break
}
return true
}
<android.support .v 4.widget .DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
//主内容
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
//toolbar的使用
<android.support .v 7.widget .Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:theme="@style/Base.ThemeOverlay.AppCompat.Dark.ActionBar" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/container" />
</LinearLayout>
//侧拉菜单
<include layout="@layout/drawer_view" />
</android.support .v 4.widget .DrawerLayout >
//初始化
actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar,
R.string .app _name, R.string .app _name)
drawerLayout.addDrawerListener (actionBarDrawerToggle)
//同步侧拉菜单和toolbar图标
actionBarDrawerToggle.syncState ()
//toolbar左上角图标的点击事件
toolbar.setNavigationOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View v) {
if (drawerLayout.isDrawerOpen (GravityCompat.START )) {
closeDrawer()
} else {
openDrawer()
}
}
})
NavigationView
//1
<android.support .design .widget .NavigationView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@color/white"
app:headerLayout="@layout/drawer_header"
app:elevation="3dp"
app:insetForeground="#4000" >
<ListView
android:id="@+id/drawer_list"
android:layout_marginTop="200dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:listSelector="?android:selectableItemBackground"
android:drawSelectorOnTop="true" />
</android.support .design .widget .NavigationView >
//2
<android.support .v 4.widget .DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" >//设置状态栏是否透明化
<!-- Your contents -->
<android.support .design .widget .NavigationView
android:id="@+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start" //出来的方向
app:menu="@menu/my_navigation_items" //menu
app:headerLayout="@layout/nav_header_main" //定制头部
/>
</android.support .v 4.widget .DrawerLayout >
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:theme="@style/Base.ThemeOverlay.AppCompat.Dark.ActionBar" />
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick (MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
Tips.showToast("Coming soon..." );
break ;
case R.id.action_about:
return WebActivity.start(MainActivity.this , WebActivity.URL_BXBXBAI, "About Me" );
}
return false ;
}
});
onPostCreate
记得之前想要在Activity布局完成,彻底跑起来之后,再获取当前Activity的窗口中,某个View的宽高,之前用的办法很土,弄个Handler ,发个Message出来,使用sendMessageDelayed或者sendEmptyMessageDelayed。
说白了就是延迟若干时间之,等Activity彻底跑起来之后,再取获取View 的宽高。
使用这个办法,总是有一种担心:delay的时间太长了,害怕使用这个获取的宽高的值的时候,自己获取宽高的函数还没被调用;delay的时间太短了,又害怕在某些配置比较低的机型上,在delay的时间内Activity没能彻底的跑起来,获取到的值可能会不正确。
//在onResume后执行
使用时钟芯片的做随机数的种子
Random r = new Random(SystemClock.elapsedRealtime ())
r.nextInt (SPLASH_ARRAY.length )
真值动画集合
ObjectAnimator animatorX = ObjectAnimator.ofFloat (mSplashImage, View.SCALE _X, 1 f, SCALE_END)
ObjectAnimator animatorY = ObjectAnimator.ofFloat (mSplashImage, View.SCALE _Y, 1 f, SCALE_END)
AnimatorSet set = new AnimatorSet()
set .setDuration (ANIMATION_DURATION).play (animatorX).with (animatorY)
set .start ()
set .addListener (new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
MainActivity.start (SplashActivity.this )
SplashActivity.this .finish ()
}
})
//以c a b顺序执行动画
animatorSet3.play (animatorA).after (animatorC).before (animatorB)
getViewTreeObserver
这是一个注册监听视图树的观察者(observer),在视图树种全局事件改变时得到通知。这个全局事件不仅还包括整个树的布局,从绘画过程开始,触摸模式的改变等。ViewTreeObserver不能够被应用程序实例化,因为它是由视图提供,参照getViewTreeObserver()以查看更多信息。
mSplashImage.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw () {
mSplashImage.getViewTreeObserver().removeOnPreDrawListener(this );
mSplashImage.buildDrawingCache();
blur(mSplashImage.getDrawingCache(), titleView);
return true ;
}
});
获取ImageView的图片缓存
Bitmap bmp = iv.getDrawingCache();
高仿bilibili客户端
github: https://github.com /HotBitmapGG/bilibili-android-client
OkHttp设置缓存
Cache cache = new Cache (new File(BilibiliApp. getInstance(). getCacheDir(), "HttpCache" ), 1024 * 1024 * 10 );
mOkHttpClient = new OkHttpClient. Builder()
. cache (cache )
. addInterceptor(interceptor)
. addNetworkInterceptor(new CacheInterceptor())
. addNetworkInterceptor(new StethoInterceptor())
. retryOnConnectionFailure(true )
. connectTimeout(30 , TimeUnit. SECONDS)
. writeTimeout(20 , TimeUnit. SECONDS)
. readTimeout(20 , TimeUnit. SECONDS)
. addInterceptor(new UserAgentInterceptor())
. build();
自定义UA
/**
* 添加UA拦截器,B站请求API需要加上UA才能正常使用
*/
private static class UserAgentInterceptor implements Interceptor {
@Override
public Response intercept (Chain chain) throws IOException {
Request originalRequest = chain.request();
Request requestWithUserAgent = originalRequest.newBuilder()
.removeHeader("User-Agent" )
.addHeader("User-Agent" , ApiConstants.COMMON_UA_STR)
.build();
return chain.proceed(requestWithUserAgent);
}
}
自定义请求头
private static class CacheInterceptor implements Interceptor {
@Override
public Response intercept (Chain chain) throws IOException {
int maxAge = 60 * 60 ;
int maxStale = 60 * 60 * 24 ;
Request request = chain.request();
if (CommonUtil.isNetworkAvailable(BilibiliApp.getInstance())) {
request = request.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build();
} else {
request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
}
Response response = chain.proceed(request);
if (CommonUtil.isNetworkAvailable(BilibiliApp.getInstance())) {
response = response.newBuilder()
.removeHeader("Pragma" )
.header("Cache-Control" , "public, max-age=" + maxAge)
.build();
} else {
response = response.newBuilder()
.removeHeader("Pragma" )
.header("Cache-Control" , "public, only-if-cached, max-stale=" + maxStale)
.build();
}
return response;
}
}
通过xml保存String[]
//res/values/strings
<?xml version="1.0" encoding="utf-8"?>
<resources >
<string-array name ="sections" >
<item > @string/section_live</item >
<item > @string/section_recommend</item >
<item > @string/section_bangumi</item >
<item > @string/section_more</item >
<item > @string/section_focus</item >
<item > @string/section_discover</item >
</string-array >
</resources >
String[] TITLES== context.getResources().getStringArray(R.array.sections);
判断网络是否可用
public static boolean isNetworkAvailable (Context context) {
NetworkInfo info = getNetworkInfo(context);
return info != null && info.isAvailable();
}
<ImageButton
android:id="@+ id/delete_username"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@android :color/transparent"
android:src="@drawable /ic_edittext_clear" />
碎片化的处理
//兼容这五种分辨率
res/values/dimens.xml
res/values-hdpi/dimens.xml
res/values-xhdpi/dimens.xml
res/values-xxhdpi/dimens.xml
res/values-xxxhdpi/dimens.xml
<resources >
<dimen name ="activity_horizontal_margin" > 16dp</dimen >
<dimen name ="default_tiny_text_size" > 12sp</dimen >
</resources >
NavigationView的使用
//需要配合Drawerlayout使用
<android.support .v 4.widget .DrawerLayout
android:id="@+id/drawer_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" >
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support .design .widget .NavigationView
android:id="@+id/navigation_view"
android:layout_width="@dimen/navigation_max_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@color/navigation_background_light"
android:overScrollMode="never"
app:headerLayout="@layout/layout_navigation_header"
app:menu="@menu/navigation_main" />
</android.support .v 4.widget .DrawerLayout >
<android.support .design .widget .NavigationView
android:id="@+id/navigation_view"
android:layout_width="@dimen/navigation_max_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@color/navigation_background_light"
android:overScrollMode="never"
//传入侧滑菜单头布局
app:headerLayout="@layout/layout_navigation_header"
//下半部分菜单栏部分
app:menu="@menu/navigation_main" />
//代码:获取到headview
View headerView = mNavigationView.getHeaderView (0 )
<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<group android:checkableBehavior="single" >
<item
android:id="@+id/item_home"
android:checked ="true"
android:icon="@drawable/ic_home_black_24dp"
android:title="@string/item_home" />
<item
android:id="@+id/item_vip"
android:checkable="false"
android:icon="@drawable/ic_nav_vip"
android:title="@string/item_vip" />
<item
android:id="@+id/item_download"
android:checkable="false"
android:icon="@drawable/ic_file_download_black_24dp"
android:title="@string/item_downloaded" />
</group >
<group
android:id="@+id/group_user"
android:checkableBehavior="single" >
<item
android:id="@+id/item_favourite"
android:icon="@drawable/ic_star_black_24dp"
android:title="@string/item_favourite" />
<item
android:id="@+id/item_history"
android:icon="@drawable/ic_history_black_24dp"
android:title="@string/item_history" />
<item
android:id="@+id/item_group"
android:icon="@drawable/ic_people_black_24dp"
android:title="@string/item_group" />
<item
android:id="@+id/item_tracker"
android:icon="@drawable/ic_account_balance_wallet_black_24dp"
android:title="@string/item_tracker" />
</group >
<group android:checkableBehavior="single" >
<item
android:id="@+id/item_theme"
android:checkable="false"
android:icon="@drawable/ic_color_lens_black_24dp"
android:title="@string/item_theme" />
<item
android:id="@+id/item_app"
android:checkable="false"
android:icon="@drawable/ic_shop_black_24dp"
android:title="@string/item_app" />
<item
android:id="@+id/item_settings"
android:icon="@drawable/ic_settings_black_24dp"
android:title="@string/item_settings" />
</group >
</menu>
mNavigationView.setNavigationItemSelectedListener(this );
@Override
public boolean onNavigationItemSelected (@NonNull MenuItem item) {
mDrawerLayout.closeDrawer(GravityCompat.START);
switch (item.getItemId()) {
case R.id.item_home:
changeFragmentIndex(item, 0 );
return true ;
case R.id.item_download:
startActivity(new Intent(MainActivity.this , OffLineDownloadActivity.class));
return true ;
case R.id.item_vip:
startActivity(new Intent(MainActivity.this , VipActivity.class));
return true ;
case R.id.item_favourite:
changeFragmentIndex(item, 1 );
return true ;
case R.id.item_history:
changeFragmentIndex(item, 2 );
return true ;
case R.id.item_group:
changeFragmentIndex(item, 3 );
return true ;
case R.id.item_tracker:
changeFragmentIndex(item, 4 );
return true ;
case R.id.item_theme:
return true ;
case R.id.item_app:
return true ;
case R.id.item_settings:
changeFragmentIndex(item, 5 );
return true ;
}
return false ;
}
圆角矩形
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android ="http://schemas.android.com/apk/res/android"
android:shape ="rectangle" >
<solid android:color ="@color/nav_head_round_background" />
<corners android:radius ="2dp" />
</shape >
切换到夜间模式
// 日间模式
AppCompatDelegate.setDefaultNightMode (AppCompatDelegate.MODE _NIGHT_NO)
// 夜间模式
AppCompatDelegate.setDefaultNightMode (AppCompatDelegate.MODE _NIGHT_YES)
//切换后调用
Acitivity.recreate ()
在控件中使用与夜间模式相关的属性
android:background="@color/colorPrimary"
判断DrawerLayout是否打开
//如果已经打开,则关闭
if (mDrawerLayout.isDrawerOpen (mDrawerLayout.getChildAt (1 ))) {
mDrawerLayout.closeDrawers ()
}
双击退出
private long exitTime;
private void exitApp () {
if (System.currentTimeMillis() - exitTime > 2000 ) {
ToastUtil.ShortToast("再按一次退出" );
exitTime = System.currentTimeMillis();
} else {
PreferenceUtil.remove(ConstantUtil.SWITCH_MODE_KEY);
finish();
}
}
自定义EmptyView
public class CustomEmptyView extends FrameLayout {
private ImageView mEmptyImg;
private TextView mEmptyText;
public CustomEmptyView (Context context) {
this (context, null );
}
public CustomEmptyView (Context context, AttributeSet attrs) {
this (context, attrs, 0 );
}
public CustomEmptyView (Context context, AttributeSet attrs, int defStyleAttr) {
super (context, attrs, defStyleAttr);
init();
setEmptyViewVisibility(true );
}
public void init () {
View view = LayoutInflater.from(getContext()).inflate(R.layout.layout_empty, this );
mEmptyImg = (ImageView) view.findViewById(R.id.empty_img);
mEmptyText = (TextView) view.findViewById(R.id.empty_text);
}
public void setEmptyImage (int imgRes) {
mEmptyImg.setImageResource(imgRes);
}
public void setEmptyText (String text) {
mEmptyText.setText(text);
}
public void setEmptyViewVisibility (boolean isVisible){
int childCount = getChildCount();
for (int i = 0 ; i < childCount; i++) {
if (i==0 ){
getChildAt(i).setVisibility(isVisible?VISIBLE:GONE);
}else {
getChildAt(i).setVisibility(isVisible?GONE:VISIBLE);
}
}
}
public void addContentView (@LayoutRes int layoutId){
LayoutInflater.from(getContext()).inflate(layoutId, this );
}
}
手机磁盘大小的获取及其格式化
/**
* 获取手机内部存储总空间
*/
public static long getPhoneTotalSize () {
if (!checkSdCard()) {
File path = Environment.getDataDirectory();
StatFs mStatFs = new StatFs(path.getPath());
long blockSizeLong = mStatFs.getBlockSizeLong();
long blockCountLong = mStatFs.getBlockCountLong();
return blockSizeLong * blockCountLong;
} else {
return getSDcardTotalSize();
}
}
/**
* 获取手机内存存储可用空间
*/
public static long getPhoneAvailableSize () {
if (!checkSdCard()) {
File path = Environment.getDataDirectory();
StatFs mStatFs = new StatFs(path.getPath());
long blockSizeLong = mStatFs.getBlockSizeLong();
long availableBlocksLong = mStatFs.getAvailableBlocksLong();
return blockSizeLong * availableBlocksLong;
} else
return getSDcardAvailableSize();
}
String totalSizeStr = Formatter.formatFileSize(this , phoneTotalSize);
String availabSizeStr = Formatter.formatFileSize(this , phoneAvailableSize);
高仿谷歌市场
recyclerView的多类型布局处理
public class HotAdapter extends RecyclerView .Adapter <RecyclerView .ViewHolder >
@Override
public RecyclerView.ViewHolder onCreateViewHolder (ViewGroup viewGroup, int type) {
if (type == BANNER) {
BannerItemHodler hodler = new BannerItemHodler(inflater.inflate(R.layout.item_banner, null ));
return hodler;
} else {
HotItemHodler hodler = new HotItemHodler(inflater.inflate(R.layout.item_live, null ),clickListener);
return hodler;
}
}
@Override
public void onBindViewHolder (RecyclerView.ViewHolder viewHolder, int i) {
if (viewHolder instanceof HotItemHodler) {
LivesBean bean = dates.get(i - 1 );
try {
setHolder(bean, (HotItemHodler) viewHolder);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (viewHolder instanceof BannerItemHodler) {
setBaner(image,(BannerItemHodler)viewHolder);
}
}
设置et的hint的字体颜色
<EditText
android:id="@+ id/search"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="@id /searchicon"
android:background="@null "
android:hint="请输入昵称/映客号"
android:textColorHint="@android :color/darker_gray"
android:singleLine="true"
android:textSize="15sp"
/>
search.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged (CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged (CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged (Editable s) {
if (!TextUtils.isEmpty(s.toString())) {
clean.setVisibility(View.VISIBLE);
doSearch(s.toString());
} else {
clean.setVisibility(View.GONE);
result.setVisibility(View.GONE);
}
}
});
实现tabLayout的效果
//初始化title
LayoutInflater inflater = LayoutInflater.from (getContext())
View view = inflater.inflate (R.layout .include _title,tabs,false)
leftSearch=(ImageView)view.findViewById (R.id .left )
scrollView = (HorizontalScrollView) view.findViewById (R.id .h _s)
LinearLayout line = (LinearLayout) view.findViewById (R.id .line )
for(int i=0
FragmentInfor info = infors.get (i)
//名字
View item_view = inflater.inflate (R.layout .item _title,null)
TextView title= (TextView) item_view.findViewById (R.id .item _title)
title.setText (info.getName ())
//linearlayout.addview 时itemview具有layoutparams
LinearLayout.LayoutParams p = new LinearLayout.LayoutParams (ViewGroup.LayoutParams .WRAP _CONTENT,ViewGroup.LayoutParams .WRAP _CONTENT)
p.setMargins (40 ,0 ,40 ,0 )
line.addView (item_view,p)
title.setTag (i)
title.setOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View v) {
int current = viewPager.getCurrentItem ()
int position = (int) v.getTag ()
if(current==position){
return
}
scrollView.smoothScrollTo (position*188 -(scrollView.getWidth ()/2 -94 ),0 )
viewPager.setCurrentItem (position)
}
})
titles.add (item_view)
}
tabs.addView (view)
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (positionOffset == 0 ){
for (int i =0 ;i<titles.size();i++){
View view = titles.get(i);
if (i!=position){
view.setScaleX(1f );
view.setScaleY(1f );
}else {
view.setScaleX(1.2f );
view.setScaleY(1.2f );
}
}
return ;
}
View view = null;
View next = null;
if (positionOffsetPixels>lastP){
next = titles.get(position+1 );
next.setScaleX(1f +(0.2f *(positionOffset)));
next.setScaleY(1f +(0.2f *(positionOffset)));
view = titles.get(position);
view.setScaleX(1.2f -(0.2f *(positionOffset)));
view.setScaleY(1.2f -(0.2f *(positionOffset)));
}else if (positionOffsetPixels<lastP){
next = titles.get(position);
next.setScaleX(1f +(0.2f *(1f -positionOffset)));
next.setScaleY(1f +(0.2f *(1f -positionOffset)));
view = titles.get(position+1 );
view.setScaleX(1.2f -(0.2f *(1f -positionOffset)));
view.setScaleY(1.2f -(0.2f *(1f -positionOffset)));
}
lastP = positionOffsetPixels;
}
@Override
public void onPageSelected(int position) {
if (position == 1 ){
View view = titles.get(1 );
ImageView down = (ImageView) view.findViewById(R.id.down);
down.setVisibility(View.VISIBLE);
}else {
View view = titles.get(1 );
ImageView down = (ImageView) view.findViewById(R.id.down);
down.setVisibility(View.GONE);
}
scrollView.smoothScrollTo(position*188 -(scrollView.getWidth()/2 -94 ),0 );
}
@Override
public void onPageScrollStateChanged(int state) {
}
Fragment的实例化处理
public class FragmentInfor {
private String name;
private Fragment fragment;
public FragmentInfor (String name, Fragment fragment) {
this .name = name;
this .fragment = fragment;
}
public String getName () {
return name;
}
public void setName (String name) {
this .name = name;
}
public Fragment getFragment () {
return fragment;
}
public void setFragment (Fragment fragment) {
this .fragment = fragment;
}
}
Class [] classes = {FocusFragment.class ,HotFragment.class ,NearFragment.class ,TalentFragment.class ,TalentFragment.class ,TalentFragment.class ,TalentFragment.class ,TalentFragment.class };
for (int i =0 ;i<titles.length;i++){
String title = titles[i];
Fragment fragment = Fragment.instantiate(getContext(),classes[i].getName());
FragmentInfor infor = new FragmentInfor(title,fragment);
infors.add(infor);
}
自定义提示小圆点
public class RingTextView extends TextView {
public RingTextView (Context context) {
super (context);
}
public RingTextView (Context context, AttributeSet attrs) {
super (context, attrs);
}
@Override
public void draw (Canvas canvas) {
Paint circlePaint = new Paint();
circlePaint.setColor(ContextCompat.getColor(getContext(), R.color.top_mes_back));
circlePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
int h = this .getHeight();
int w = this .getWidth();
int diameter =Math.max(h,w);
this .setHeight(diameter);
this .setWidth(diameter);
int radius = diameter/2 ;
canvas.drawCircle(diameter / 2 , diameter / 2 , radius, circlePaint);
super .draw(canvas);
}
}
Fragment的处理
private void addMine (FragmentManager fragmentManager, MineFragment mineFragment) {
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(R.id.top, mineFragment, MINE);
transaction.commit();
}
private void showMine (FragmentManager fragmentManager, MineFragment mineFragment) {
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.show(mineFragment);
transaction.commit();
}
private void hideMine (FragmentManager fragmentManager, MineFragment mineFragment) {
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.hide(mineFragment);
transaction.commit();
}
FragmentManager fragmentManager = getSupportFragmentManager();
MineFragment mineFragment =
(MineFragment) fragmentManager.findFragmentByTag(MINE);
LiveFragment liveFragment =
(LiveFragment) fragmentManager.findFragmentByTag(LIVE);
if (null != liveFragment) {
hideLive(fragmentManager, liveFragment);
}
if (null == mineFragment) {
mineFragment = new MineFragment();
addMine(fragmentManager, mineFragment);
} else {
showMine(fragmentManager, mineFragment);
}
selector的处理
//将点击事件交给viewgroup处理
<LinearLayout
android:id ="@+id/live"
android:layout_width ="0dp"
android:layout_height ="match_parent"
android:layout_marginRight ="35dp"
android:layout_weight ="1"
android:clickable ="true"
android:gravity ="center"
android:orientation ="horizontal" >
<ImageView
android:layout_width ="35dp"
android:layout_height ="35dp"
android:background ="@drawable/tab_live_selector" />
</LinearLayout >
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android ="http://schemas.android.com/apk/res/android" >
<item android:state_selected ="true" android:drawable ="@drawable/tab_live_p" />
<item android:state_pressed ="true" android:drawable ="@drawable/tab_live_p" />
<item android:state_focused ="true" android:drawable ="@drawable/tab_live_p" />
<item android:drawable ="@drawable/tab_live" />
</selector >
官方侧滑菜单
compile 'com.android.support:appcompat-v7:25.3.1'
<android.support .v 4.widget .DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
//侧滑菜单部分
<FrameLayout
android:layout_width="180dp"
android:layout_height="match_parent"
android:layout_gravity="left"
android:background="#f00"
/>
//内容部分
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com .astuetz .PagerSlidingTabStrip
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="48dip"
app:pstsIndicatorHeight="1dp"
app:pstsIndicatorColor="#f00" />
<android.support .v 4.view .ViewPager
android:id="@+id/main_vp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</android.support .v 4.widget .DrawerLayout >
mDrawerLayout = (DrawerLayout) findViewById(R.id.activity_main);
ActionBarDrawerToggle mToggle = new ActionBarDrawerToggle(this , mDrawerLayout, R.string.open,R.string.close);
mToggle.syncState();
mDrawerLayout.setDrawerListener(mToggle);
@Override
public boolean onOptionsItemSelected (MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
mToggle.onOptionsItemSelected(item);
break ;
}
return super .onOptionsItemSelected(item);
}
线程池
public class ThreadPoolFactory {
private static ThreadPoolProxy ThreadPoolProxyNormal;
private static ThreadPoolProxy ThreadPoolProxyDownLoad;
public static ThreadPoolProxy cureatThreadPoolProxyNormal (){
if (ThreadPoolProxyNormal == null ){
ThreadPoolProxyNormal = new ThreadPoolProxy(3 ,3 ,3000 );
}
return ThreadPoolProxyNormal;
}
public static ThreadPoolProxy cureatThreadPoolProxyDownLoad (){
if (ThreadPoolProxyDownLoad == null ){
ThreadPoolProxyDownLoad = new ThreadPoolProxy(3 ,3 ,3000 );
}
return ThreadPoolProxyDownLoad;
}
}
public class ThreadPoolProxy {
private int mCorePoolSize;
private int mMaximumPoolSize;
private long mKeepAliveTime;
private ThreadPoolExecutor mPoolExecutor;
public ThreadPoolProxy (int corePoolSize, int maximumPoolSize, long keepAliveTime) {
mCorePoolSize = corePoolSize;
mMaximumPoolSize = maximumPoolSize;
mKeepAliveTime = keepAliveTime;
}
public void initThreadPoolExecutor (){
if (mPoolExecutor ==null || mPoolExecutor.isShutdown() || mPoolExecutor.isTerminated()){
synchronized (ThreadPoolProxy.class){
TimeUnit unit = TimeUnit.MICROSECONDS;
BlockingQueue<Runnable> workQueue = new LinkedBlockingDeque<>();
ThreadFactory threadFactory = Executors.defaultThreadFactory();
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
mPoolExecutor = new ThreadPoolExecutor(
mCorePoolSize,
mMaximumPoolSize,
mKeepAliveTime,
unit,
workQueue,
threadFactory,
handler);
}
}
}
public void submit (Runnable task){
initThreadPoolExecutor();
mPoolExecutor.submit(task);
}
public void cxecute (Runnable task){
initThreadPoolExecutor();
mPoolExecutor.execute(task);
}
public void remove (Runnable task){
initThreadPoolExecutor();
mPoolExecutor.remove(task);
}
}
某马手机卫士…不是很有必要看
打开设备管理器,激活高级权限
public class MyDevice extends DeviceAdminReceiver {
}
DevicePolicyManager manager = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE)
mComponentName = new ComponentName(this,MyDevice.class )
//激活权限
Intent intent = new Intent(DevicePolicyManager.ACTION _ADD_DEVICE_ADMIN)
intent.putExtra (DevicePolicyManager.EXTRA _DEVICE_ADMIN, mComponentName)
intent.putExtra (DevicePolicyManager.EXTRA _ADD_EXPLANATION,
"快来激活软件,否则罚款" )
startActivity(intent)
//取消激活
manager.removeActiveAdmin (mComponentName)
获取联系人
public class ContactsUtils {
public static List<Contact> getContacts (Context context){
List<Contact> lists=new ArrayList<>();
ContentResolver resolver = context.getContentResolver();
Uri contactUri=Uri.parse("content://com.android.contacts/contacts" );
Uri uri=Uri.parse("content://com.android.contacts/data" );
Cursor contactCursor = resolver.query(contactUri, new String[]{"_id" }, null , null , null );
while (contactCursor.moveToNext()){
String id = contactCursor.getString(0 );
if (!TextUtils.isEmpty(id)) {
Contact contact=new Contact();
Cursor cursor = resolver.query(uri, new String[]{"mimetype" , "data1" }, "raw_contact_id=?" , new String[]{id}, null );
while (cursor.moveToNext()){
String mimetype = cursor.getString(0 );
String data1 = cursor.getString(1 );
if ("vnd.android.cursor.item/phone_v2" .equals(mimetype)) {
contact.phone=data1;
}else if ("vnd.android.cursor.item/name" .equals(mimetype)) {
contact.name=data1;
}
}
lists.add(contact);
}
}
return lists;
}
}
手势识别,总算有个不错的
public abstract class BaseSetupActivity extends Activity {
private GestureDetector detector;
@Override
protected void onCreate (@Nullable Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
initView();
initData();
initEvent();
detector = new GestureDetector(this , new GestureDetector.SimpleOnGestureListener() {
/**
* @param e1 事件1 开始手指放下去的事件
* @param e2 事件2 手指离开的事件
* @param velocityX x轴的方向的分量
* @param velocityY y轴方向的分量
* @return
*/
@Override
public boolean onFling (MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (e1.getRawX() - e2.getRawX() > 20 ) {
showNext();
overridePendingTransition(R.anim.next_enter, R.anim.next_exit);
}
if (e2.getRawX() - e1.getRawX() > 20 ) {
showPre();
overridePendingTransition(R.anim.pre_enter, R.anim.pre_exit);
}
return super .onFling(e1, e2, velocityX, velocityY);
}
});
}
/**
* 所有的屏幕触摸事件最先激活的,或者接受的方法是onTouchEvent
* @param event 就是触摸屏幕的时间
* @return
*/
@Override
public boolean onTouchEvent (MotionEvent event) {
detector.onTouchEvent(event);
return super .onTouchEvent(event);
}
protected abstract void initView ();
protected abstract void initData ();
protected abstract void initEvent ();
protected abstract void showNext ();
protected abstract void showPre ();
}
//next_enter
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android ="http://schemas.android.com/apk/res/android"
android:duration ="300"
android:fromXDelta ="100%p"
android:fromYDelta ="0"
android:toXDelta ="0"
android:toYDelta ="0" />
//next_exit
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android ="http://schemas.android.com/apk/res/android"
android:duration ="300"
android:fromXDelta ="0"
android:fromYDelta ="0"
android:toXDelta ="-100%p"
android:toYDelta ="0" />
//pre_enter
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android ="http://schemas.android.com/apk/res/android"
android:duration ="300"
android:fromXDelta ="-100%p"
android:fromYDelta ="0"
android:toXDelta ="0"
android:toYDelta ="0" />
//pre_exit
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android ="http://schemas.android.com/apk/res/android"
android:duration ="300"
android:fromXDelta ="0"
android:fromYDelta ="0"
android:toXDelta ="100%p"
android:toYDelta ="0" />
自定义属性
//res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources >
<declare-styleable name ="MyRelative" >
<attr name ="mytext" format ="string" > </attr >
<attr name ="myType" >
<enum name ="first" value ="0" />
<enum name ="middle" value ="1" />
<enum name ="last" value ="2" />
</attr >
</declare-styleable >
</resources >
public class MyRelative extends RelativeLayout {
private RelativeLayout mSet_rl;
private TextView mSet_name;
private ImageView mSet_update;
private boolean isOpen;
public MyRelative (Context context) {
this (context, null );
}
public MyRelative (Context context, AttributeSet attrs) {
super (context, attrs);
initView(context);
initData(attrs);
}
private void initView (Context context) {
View.inflate(context, R.layout.view_rl, this );
mSet_rl = (RelativeLayout) findViewById(R.id.set_item_update);
mSet_name = (TextView) findViewById(R.id.set_item_tv_name);
mSet_update = (ImageView) findViewById(R.id.set_item_iv_update);
}
public void setImageViewState (boolean isOpen) {
this .isOpen = isOpen;
if (isOpen) {
mSet_update.setImageResource(R.mipmap.on);
} else {
mSet_update.setImageResource(R.mipmap.off);
}
}
private void initData (AttributeSet attrs) {
String mytext = attrs.getAttributeValue("http://schemas.android.com/apk/res-auto" , "mytext" );
mSet_name.setText(mytext);
String myType = attrs.getAttributeValue("http://schemas.android.com/apk/res-auto" , "myType" );
switch (Integer.parseInt(myType)) {
case 0 :
mSet_rl.setBackgroundResource(R.drawable.set_item_first_backgtound);
break ;
case 1 :
mSet_rl.setBackgroundResource(R.drawable.set_item_middle_backgtound);
break ;
case 2 :
mSet_rl.setBackgroundResource(R.drawable.set_item_last_backgtound);
break ;
}
}
}
<com .heima .mobilsafe .view .MyRelative
gaga:mytext="开启自动更新"
android:layout_marginTop="20dp"
android:id="@+id/myrl_update"
gaga:myType="first"
android:layout_width="match_parent"
android:layout_height="40dp"
/>
AlertDialog不需要继承实现自定义view的方法
AlertDialog.Builder builder=new AlertDialog.Builder (this)
View view = View.inflate (getApplicationContext(), R.layout .view _set_password, null)
mEt_password = (EditText) view.findViewById (R.id .view _et_setpassword)
mEt_conf_password = (EditText) view.findViewById (R.id .view _et_comf_setpassword)
mBtn_cancel = (Button) view.findViewById (R.id .view _btn_cancel)
mBtn_ok = (Button) view.findViewById (R.id .view _btn_ok)
//取消的点击事件
mBtn_cancel.setOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View v) {
mDialog.dismiss ()
}
})
mBtn_ok.setOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View v) {
// 1 获取值
String passwprd = mEt_password.getText ().toString ().trim ()
String passwrod_conf = mEt_conf_password.getText ().toString ().trim ()
// 2 非空判断
if(TextUtils.isEmpty (passwprd)||TextUtils.isEmpty (passwrod_conf)) {
Toast.makeText (HomeActivity.this , "请按要求输入" , Toast.LENGTH _SHORT).show ()
// 3 判断密码是否相等
}else if(passwprd.equals (passwrod_conf)) {
SpUtils.setString (getApplicationContext(),Constants.PASSWORD ,passwprd)
// 4 保存且关闭对话框
mDialog.dismiss ()
}else{
Toast.makeText (HomeActivity.this , "密码输入不一致" , Toast.LENGTH _SHORT).show ()
}
}
})
builder.setView (view)
mDialog = builder.show ()
无限动画
//设置旋转动画
ObjectAnimator rotation = ObjectAnimator.ofFloat (mHome_logo, "rotationY" , 0 , 30 , 90 , 120 , 160 , 190 , 260 , 360 )
//设置动画永远重复
rotation.setRepeatCount (ObjectAnimator.INFINITE )
//动画作用时常
rotation.setDuration (2000 )
//开启动画
rotation.start ()
TextView文字滚动
<TextView
android:id="@+id/music_name_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee" 【必须】
android:focusable="true" 【必须】
android:focusableInTouchMode="true" 【必须】
android:lines ="1" 【必须】
android:text ="我的中国心我的中国心我的中国心我的中国心我的中国心我的中国心我的中国心我的中国心我的中国心xxxx"
android:textColor="@color/colorAccent"
android:textSize="15sp" />
public static void setTextMarquee (TextView textView) {
if (textView != null ) {
textView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
textView.setSingleLine(true );
textView.setSelected(true );
textView.setFocusable(true );
textView.setFocusableInTouchMode(true );
}
}
FragmentManager对应的生命周期
add(R.id.content,fristFragment,"handsome" ) ;->添加到指定的父控件,一层叠加一层
remove() ;把一个Fragment彻底删除onDetach
replace(R.id.content,fristFragment,"handsome" ) ;
detach() 解绑,onDestroyView
attach() 重新绑定 onCreateView
show() 不会调用任何生命周期方法
hide()
属性动画重要属性
public static ValueAnimator ofFloat (float ... values)
public static ValueAnimator ofInt (int ... values)
* public final class ObjectAnimator extends ValueAnimator
public static ObjectAnimator ofFloat (Object target, String propertyName, float ... values)
public static <T> ObjectAnimator ofInt (T target, Property<T, Integer> property, int ... values)
android 3.0也可以执行属性动画
使用nineoldandroids-2.2 .0 .jar
AnimationSet
RotateAnimation rt = new RotateAnimation(0.0f , 360.0f , Animation.RELATIVE_TO_SELF, 0.5f , Animation.RELATIVE_TO_SELF, 0.5f );
rt.setDuration(2000 );
rt.setFillAfter(true );
ScaleAnimation sa = new ScaleAnimation(0.0f , 1.0f , 0.0f , 1.0f , Animation.RELATIVE_TO_SELF, 0.5f , Animation.RELATIVE_TO_SELF, 0.5f );
sa.setDuration(2000 );
AlphaAnimation at = new AlphaAnimation(0.0f , 1.0f );
at.setDuration(2000 );
mSet = new AnimationSet(false );
mSet.addAnimation(rt);
mSet.addAnimation(sa);
mSet.addAnimation(at);
mSplash_root.startAnimation(mSet);
使用Xutils实现apk下载和安装
HttpUtils httpUtils=new HttpUtils();
final File file=new File(Environment.getExternalStorageDirectory(),"xxx.apk" );
httpUtils.download(data.downloadurl, file.getAbsolutePath(), false , new RequestCallBack<File>() {
@Override
public void onSuccess (ResponseInfo<File> responseInfo) {
Toast.makeText(SplashActivity.this , "下载成功" , Toast.LENGTH_SHORT).show();
Intent intent=new Intent();
intent.setAction("android.intent.action.VIEW" );
intent.addCategory("android.intent.category.DEFAULT" );
intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive" );
startActivityForResult(intent,1 );
}
@Override
public void onFailure (HttpException e, String s) {
}
});
private String paramsStream (InputStream in ) throws IOException {
StringBuffer sb=new StringBuffer();
BufferedReader reader=new BufferedReader(new InputStreamReader(in ));
String line = reader.readLine();
while (line!=null ){
sb.append(line);
line= reader.readLine();
}
return sb.toString();
}
山寨网易newsClient
利用space来为linearlayout占据位置
<LinearLayout
android:layout_width ="match_parent"
android:layout_height ="50dp"
android:orientation ="horizontal" >
<ImageButton
android:src ="@drawable/news_title_back"
android:background ="@drawable/bg_btn_back"
android:layout_width ="50dp"
android:layout_height ="match_parent"
/>
//一个空白
<Space
android:layout_width ="0dp"
android:layout_weight ="1"
android:layout_height ="wrap_content" />
<ImageButton
android:background ="@drawable/bg_btn_back"
android:src ="@drawable/news_title_menu"
android:layout_width ="50dp"
android:layout_height ="match_parent"
/>
</LinearLayout >
自定义广告轮播图控件
//资源文件
//R.layout.view_banner
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android ="http://schemas.android.com/apk/res/android"
android:layout_width ="match_parent"
android:layout_height ="180dp" >
<android.support.v4.view.ViewPager
android:layout_width ="match_parent"
android:layout_height ="match_parent"
android:id ="@+id/viewPager_banner" />
<LinearLayout
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
android:gravity ="center_vertical"
android:orientation ="horizontal"
android:layout_alignParentBottom ="true"
android:paddingLeft ="8dp"
android:paddingBottom ="8dp"
android:paddingRight ="8dp"
android:background ="@drawable/bg_banner_bottom"
>
<TextView
android:id ="@+id/tv_banner"
android:layout_width ="0dp"
android:layout_weight ="1"
android:layout_height ="wrap_content"
android:textColor ="@color/colorWhite"
android:text ="我是轮播图标题" />
<LinearLayout
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:id ="@+id/ll_dot"
android:orientation ="horizontal" />
</LinearLayout >
</RelativeLayout >
//R.drawable.bg_dot
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android ="http://schemas.android.com/apk/res/android" android:shape ="rectangle" >
<size android:width ="8dp" android:height ="8dp" />
<corners android:radius ="6dp" />
<solid android:color ="@color/colorWhite" />
</shape >
//R.drawable.bg_selected
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android ="http://schemas.android.com/apk/res/android" android:shape ="rectangle" >
<size android:width ="8dp" android:height ="8dp" />
<corners android:radius ="6dp" />
<solid android:color ="@color/colorGray" />
</shape >
public class BannerView extends RelativeLayout {
private int mPicSize;
private Handler mHandler;
private BannerPagerAdapter mBannerPagerAdapter;
public BannerView (Context context) {
super (context);
init();
}
private ArrayList<String> mPicUrls;
private ArrayList<String> mTitles;
private ViewPager mViewPagerBanner;
private TextView mTvBanner;
private LinearLayout mLlDot;
public BannerView (Context context, ArrayList<String> picUrls, ArrayList<String> titles) {
super (context);
mPicUrls = picUrls;
mTitles = titles;
mPicSize = mPicUrls.size();
init();
}
private void init () {
View inflate = View.inflate(getContext(), R.layout.view_banner, this );
mViewPagerBanner = (ViewPager) inflate.findViewById(R.id.viewPager_banner);
mTvBanner = (TextView) inflate.findViewById(R.id.tv_banner);
mLlDot = (LinearLayout) inflate.findViewById(R.id.ll_dot);
ArrayList<ImageView> imageViews = new ArrayList<>();
for (int i = 0 ; i < mPicSize; i++) {
ImageView imageView = new ImageView(getContext());
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
ImageUtil.getSingleton().display(mPicUrls.get(i), imageView);
imageViews.add(imageView);
}
mBannerPagerAdapter = new BannerPagerAdapter(imageViews);
mViewPagerBanner.setAdapter(mBannerPagerAdapter);
MyPageChangeListener myPageChangeListener = new MyPageChangeListener();
mViewPagerBanner.addOnPageChangeListener(myPageChangeListener);
mHandler = new Handler() {
@Override
public void handleMessage (Message msg) {
super .handleMessage(msg);
int currentItem = mViewPagerBanner.getCurrentItem();
mViewPagerBanner.setCurrentItem(currentItem + 1 );
mHandler.sendEmptyMessageDelayed(0 , 2000 );
}
};
initDot();
}
@Override
public boolean dispatchTouchEvent (MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
mHandler.removeCallbacksAndMessages(null );
break ;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mHandler.sendEmptyMessageDelayed(0 ,2000 );
break ;
default :
break ;
}
return super .dispatchTouchEvent(ev);
}
private void initDot () {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(-2 ,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0 , 0 , 10 , 0 );
for (int i = 0 ; i < mPicSize; i++) {
ImageView imageView = new ImageView(getContext());
imageView.setImageResource(R.drawable.bg_dot);
mLlDot.addView(imageView, params);
}
mViewPagerBanner.setCurrentItem((Integer.MAX_VALUE / 2 ) - Integer.MAX_VALUE / 2 % mPicSize);
mHandler.sendEmptyMessageDelayed(0 , 2000 );
}
private void selectDot (int i) {
mTvBanner.setText(mTitles.get(i));
int childCount = mLlDot.getChildCount();
for (int j = 0 ; j < childCount; j++) {
ImageView child = (ImageView) mLlDot.getChildAt(j);
if (j == i) {
child.setImageResource(R.drawable.bg_dot_selected);
} else {
child.setImageResource(R.drawable.bg_dot);
}
}
}
public BannerView (Context context, @Nullable AttributeSet attrs) {
super (context, attrs);
}
public void updateData (ArrayList<String> picUrls, ArrayList<String> titles) {
mPicUrls = picUrls;
mTitles = titles;
mPicSize = mPicUrls.size();
ArrayList<ImageView> imageViews = new ArrayList<>();
for (int i = 0 ; i < mPicSize; i++) {
ImageView imageView = new ImageView(getContext());
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
ImageUtil.getSingleton().display(mPicUrls.get(i), imageView);
imageViews.add(imageView);
}
if (mBannerPagerAdapter!=null ){
mBannerPagerAdapter.updateData(imageViews);
}
mLlDot.removeAllViews();
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(-2 ,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0 , 0 , 10 , 0 );
for (int i = 0 ; i < mPicSize; i++) {
ImageView imageView = new ImageView(getContext());
imageView.setImageResource(R.drawable.bg_dot);
mLlDot.addView(imageView, params);
}
mHandler.removeCallbacksAndMessages(null );
mHandler.sendEmptyMessageDelayed(0 , 2000 );
}
class MyPageChangeListener implements ViewPager.OnPageChangeListener {
@Override
public void onPageScrolled (int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected (int position) {
selectDot(position % mPicSize);
}
@Override
public void onPageScrollStateChanged (int state) {
}
}
}
public class BannerPagerAdapter extends PagerAdapter {
private ArrayList<ImageView> mImageViews;
public BannerPagerAdapter (ArrayList<ImageView> imageViews) {
mImageViews = imageViews;
}
@Override
public int getCount () {
return Integer.MAX_VALUE;
}
@Override
public boolean isViewFromObject (View view, Object object) {
return view==object;
}
@Override
public Object instantiateItem (ViewGroup container, int position) {
ImageView imageView = mImageViews.get(position%mImageViews.size());
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem (ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
public void updateData (ArrayList<ImageView> imageViews) {
mImageViews.clear();
mImageViews.addAll(imageViews);
notifyDataSetChanged();
}
}
mBannerView = new BannerView(getContext(),picUrls,titles);
listview自定义加载更多
lv.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged (AbsListView view, int scrollState) {
if (scrollState== AbsListView.OnScrollListener.SCROLL_STATE_IDLE){
int lastVisiblePosition = mLvHot.getLastVisiblePosition();
int count = mLvHot.getAdapter().getCount();
Log.e(getClass().getSimpleName() + "xmg" , "onScrollStateChanged: " + "lastVisiblePosition" +
lastVisiblePosition+" count:" +count);
if (lastVisiblePosition==count-1 ){
requestData(true );
}
}
}
@Override
public void onScroll (AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
ViewGroup触摸事件的拦截和处理
public class MyPtrClassicFrameLayout extends PtrClassicFrameLayout {
public MyPtrClassicFrameLayout (Context context) {
super (context);
}
public MyPtrClassicFrameLayout (Context context, AttributeSet attrs) {
super (context, attrs);
}
float mStartX = 0 ;
float mStartY = 0 ;
float mOffsetX = 0 ;
float mOffsetY = 0 ;
@Override
public boolean dispatchTouchEvent (MotionEvent event) {
int eventAction = event.getAction();
switch (eventAction) {
case MotionEvent.ACTION_DOWN:
mStartX = event.getX();
mStartY = event.getY();
mOffsetX = 0 ;
mOffsetY = 0 ;
break ;
case MotionEvent.ACTION_MOVE:
float newX = event.getX();
float newY = event.getY();
float dx = newX-mStartX;
float dy = newY-mStartY;
mOffsetX+=dx;
mOffsetY+=dy;
if (Math.abs(mOffsetX)> ViewConfiguration.getTouchSlop()&&
Math.abs(mOffsetX)>Math.abs(mOffsetY)){
return dispatchTouchEventSupper(event);
}
mStartX = newX;
mStartY = newY;
break ;
case MotionEvent.ACTION_UP:
break ;
}
return super .dispatchTouchEvent(event);
}
}
xml保存数据:strings
//R.values.strings
<resources >
<string name ="app_name" > NewsReader08</string >
<array name ="news_titles" >
<item > 头条</item >
<item > 要闻</item >
<item > 娱乐</item >
<item > 体育</item >
<item > 网易号</item >
<item > 北京</item >
<item > 视频</item >
<item > 财经</item >
<item > 科技</item >
<item > 汽车</item >
<item > 时尚</item >
<item > 图片</item >
<item > 直播</item >
<item > 热点</item >
<item > 跟贴</item >
<item > 房产</item >
<item > 股票</item >
</array >
<array name ="to_add_news_titles" >
<item > 轻松一刻</item >
<item > 段子</item >
<item > 美女</item >
</array >
</resources >
//代码中获取
String [] stringArray = getResources().getStringArray(R.array.news_titles);
List <String > strings = Arrays .asList(stringArray);
view的隐藏可见与animation的配合使用
mTranslateAnimShow = new TranslateAnimation
(TranslateAnimation.RELATIVE _TO_SELF, 0 ,
TranslateAnimation.RELATIVE _TO_SELF, 0 ,
TranslateAnimation.RELATIVE _TO_SELF, -1 ,
TranslateAnimation.RELATIVE _TO_SELF, 0 )
mTranslateAnimShow.setDuration (1000 )
mFlChangeTitle.setVisibility (View.VISIBLE )
mFlChangeTitle.startAnimation (mTranslateAnimShow)
FragmentTabHost的使用
//1 初始化 把它需要的参数,比如FragmentManager传过去
mTabHost.setup (getApplicationContext(),getSupportFragmentManager(),R.id .fl _content)
int[] resIds = new int[]{R.drawable .tab _news,R.drawable .tab _va,R.drawable .tab _topic,R.drawable .tab _my}
String[] tabTexts = new String[]{"新闻" ,"直播" ,"话题" ,"我的" }
Class[] fragments = new Class[]{NewsFragment.class , VaFragment.class , TopicFragment.class , MeFragment.class }
//2 接下来开始放入一个个Tab进来
for (int i = 0
TabHost.TabSpec tabSpec = mTabHost.newTabSpec (String.valueOf (i))
//需要指定这个Tab的长相
View inflate = View.inflate (getApplicationContext(), R.layout .item _tab, null)
ImageView ivTab = (ImageView) inflate.findViewById (R.id .iv _tab)
TextView tvTab = (TextView) inflate.findViewById (R.id .tv _tab)
ivTab.setImageResource (resIds[i])
tvTab.setText (tabTexts[i])
tabSpec.setIndicator (inflate)
Class fragmentClazz = fragments[i]
mTabHost.addTab (tabSpec,fragmentClazz ,null)
}
mTabHost.setOnTabChangedListener (new TabHost.OnTabChangeListener () {
@Override
public void onTabChanged(String tabId) {
Toast.makeText (HomeActivity.this , "你切换到了:" +tabId, Toast.LENGTH _SHORT).show ()
}
})
修改FragmentTabhost为 hide show
public class MyFragmentTabHost extends TabHost
implements TabHost .OnTabChangeListener {
private final ArrayList<TabInfo> mTabs = new ArrayList<>();
private FrameLayout mRealTabContent;
private Context mContext;
private FragmentManager mFragmentManager;
private int mContainerId;
private OnTabChangeListener mOnTabChangeListener;
private TabInfo mLastTab;
private boolean mAttached;
static final class TabInfo {
final @NonNull String tag;
final @NonNull Class<?> clss;
final @Nullable Bundle args;
Fragment fragment;
TabInfo(@NonNull String _tag, @NonNull Class<?> _class, @Nullable Bundle _args) {
tag = _tag;
clss = _class;
args = _args;
}
}
static class DummyTabFactory implements TabContentFactory {
private final Context mContext;
public DummyTabFactory (Context context) {
mContext = context;
}
@Override
public View createTabContent (String tag) {
View v = new View(mContext);
v.setMinimumWidth(0 );
v.setMinimumHeight(0 );
return v;
}
}
static class SavedState extends BaseSavedState {
String curTab;
SavedState(Parcelable superState) {
super (superState);
}
SavedState(Parcel in) {
super (in);
curTab = in.readString();
}
@Override
public void writeToParcel (Parcel out, int flags) {
super .writeToParcel(out, flags);
out.writeString(curTab);
}
@Override
public String toString () {
return "FragmentTabHost.SavedState{"
+ Integer.toHexString(System.identityHashCode(this ))
+ " curTab=" + curTab + "}" ;
}
public static final Creator<SavedState> CREATOR
= new Creator<SavedState>() {
@Override
public SavedState createFromParcel (Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray (int size) {
return new SavedState[size];
}
};
}
public MyFragmentTabHost (Context context) {
super (context, null );
initFragmentTabHost(context, null );
}
public MyFragmentTabHost (Context context, AttributeSet attrs) {
super (context, attrs);
initFragmentTabHost(context, attrs);
}
private void initFragmentTabHost (Context context, AttributeSet attrs) {
final TypedArray a = context.obtainStyledAttributes(attrs,
new int [] { android.R.attr.inflatedId }, 0 , 0 );
mContainerId = a.getResourceId(0 , 0 );
a.recycle();
super .setOnTabChangedListener(this );
}
private void ensureHierarchy (Context context) {
if (findViewById(android.R.id.tabs) == null ) {
LinearLayout ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.VERTICAL);
addView(ll, new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
TabWidget tw = new TabWidget(context);
tw.setId(android.R.id.tabs);
tw.setOrientation(TabWidget.HORIZONTAL);
ll.addView(tw, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 0 ));
FrameLayout fl = new FrameLayout(context);
fl.setId(android.R.id.tabcontent);
ll.addView(fl, new LinearLayout.LayoutParams(0 , 0 , 0 ));
mRealTabContent = fl = new FrameLayout(context);
mRealTabContent.setId(mContainerId);
ll.addView(fl, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, 0 , 1 ));
}
}
/**
* @deprecated Don't call the original TabHost setup, you must instead
* call {@link #setup(Context, FragmentManager)} or
* {@link #setup(Context, FragmentManager, int)}.
*/
@Override @Deprecated
public void setup () {
throw new IllegalStateException(
"Must call setup() that takes a Context and FragmentManager" );
}
public void setup (Context context, FragmentManager manager) {
ensureHierarchy(context);
super .setup();
mContext = context;
mFragmentManager = manager;
ensureContent();
}
public void setup (Context context, FragmentManager manager, int containerId) {
ensureHierarchy(context);
super .setup();
mContext = context;
mFragmentManager = manager;
mContainerId = containerId;
ensureContent();
mRealTabContent.setId(containerId);
if (getId() == View.NO_ID) {
setId(android.R.id.tabhost);
}
}
private void ensureContent () {
if (mRealTabContent == null ) {
mRealTabContent = (FrameLayout)findViewById(mContainerId);
if (mRealTabContent == null ) {
throw new IllegalStateException(
"No tab content FrameLayout found for id " + mContainerId);
}
}
}
@Override
public void setOnTabChangedListener (OnTabChangeListener l) {
mOnTabChangeListener = l;
}
public void addTab (@NonNull TabSpec tabSpec, @NonNull Class<?> clss,
@Nullable Bundle args) {
tabSpec.setContent(new DummyTabFactory(mContext));
final String tag = tabSpec.getTag();
final TabInfo info = new TabInfo(tag, clss, args);
if (mAttached) {
info.fragment = mFragmentManager.findFragmentByTag(tag);
if (info.fragment != null && !info.fragment.isDetached()) {
final FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.detach(info.fragment);
ft.commit();
}
}
mTabs.add(info);
addTab(tabSpec);
}
@Override
protected void onAttachedToWindow () {
super .onAttachedToWindow();
final String currentTag = getCurrentTabTag();
FragmentTransaction ft = null ;
for (int i = 0 , count = mTabs.size(); i < count; i++) {
final TabInfo tab = mTabs.get(i);
tab.fragment = mFragmentManager.findFragmentByTag(tab.tag);
if (tab.fragment != null && !tab.fragment.isDetached()) {
if (tab.tag.equals(currentTag)) {
mLastTab = tab;
} else {
if (ft == null ) {
ft = mFragmentManager.beginTransaction();
}
ft.detach(tab.fragment);
}
}
}
mAttached = true ;
ft = doTabChanged(currentTag, ft);
if (ft != null ) {
ft.commit();
mFragmentManager.executePendingTransactions();
}
}
@Override
protected void onDetachedFromWindow () {
super .onDetachedFromWindow();
mAttached = false ;
}
@Override
protected Parcelable onSaveInstanceState () {
Parcelable superState = super .onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.curTab = getCurrentTabTag();
return ss;
}
@Override
protected void onRestoreInstanceState (Parcelable state) {
if (!(state instanceof SavedState)) {
super .onRestoreInstanceState(state);
return ;
}
SavedState ss = (SavedState) state;
super .onRestoreInstanceState(ss.getSuperState());
setCurrentTabByTag(ss.curTab);
}
@Override
public void onTabChanged (String tabId) {
if (mAttached) {
final FragmentTransaction ft = doTabChanged(tabId, null );
if (ft != null ) {
ft.commit();
}
}
if (mOnTabChangeListener != null ) {
mOnTabChangeListener.onTabChanged(tabId);
}
}
@Nullable
private FragmentTransaction doTabChanged (@Nullable String tag,
@Nullable FragmentTransaction ft) {
final TabInfo newTab = getTabInfoForTag(tag);
if (mLastTab != newTab) {
if (ft == null ) {
ft = mFragmentManager.beginTransaction();
}
if (mLastTab != null ) {
if (mLastTab.fragment != null ) {
ft.hide(mLastTab.fragment);
}
}
if (newTab != null ) {
if (newTab.fragment == null ) {
newTab.fragment = Fragment.instantiate(mContext,
newTab.clss.getName(), newTab.args);
ft.add(mContainerId, newTab.fragment, newTab.tag);
} else {
if (newTab.fragment.isHidden()){
ft.show(newTab.fragment);
}
}
}
mLastTab = newTab;
}
return ft;
}
@Nullable
private TabInfo getTabInfoForTag (String tabId) {
for (int i = 0 , count = mTabs.size(); i < count; i++) {
final TabInfo tab = mTabs.get(i);
if (tab.tag.equals(tabId)) {
return tab;
}
}
return null ;
}
}
获取hashcode
public class HashUtil {
public static String getHashCodeFileName (String picUrl){
int hashCode = picUrl.hashCode();
return hashCode+".jpg" ;
}
}
使用缓存目录
File file = new File (getExternalCacheDir(), HashUtil.getHashCodeFileName(picUrl));
画笔测量文字大小
mMeasureTextWidth = mTextPaint.measureText(TEXT);
自定义控件的动画效果
mHandler = new Handler() {
@Override
public void handleMessage (Message msg) {
super .handleMessage(msg);
mCurcentTime += 100 ;
if (mCurcentTime >= mTotalTime) {
mCurcentTime = mTotalTime;
invalidate();
if (mOnSkipListener!=null ){
mOnSkipListener.onSkip();
}
Toast.makeText(getContext(), "我要关闭该页面了" , Toast.LENGTH_SHORT).show();
return ;
}
invalidate();
mHandler.sendEmptyMessageDelayed(0 , 100 );
}
};
自定义广告页中的可以点击跳过的圆形view
public class SkipView extends View {
public static final int ARC_WIDTH = 5 ;
public static final int TEXT_PADDING = 8 ;
public static final int TEXT_SIZE = 16 ;
public static final String TEXT = "跳过" ;
private Paint mOutArcPaint;
private Paint mInnerCirclePaint;
private Paint mTextPaint;
private float mMeasureTextWidth;
private float mInnerCircleDoubleRadius;
private float mOutArcDoubleRadius;
private RectF mRectF;
private Handler mHandler;
public SkipView (Context context) {
super (context);
}
public SkipView (Context context, @Nullable AttributeSet attrs) {
super (context, attrs);
init();
}
private void init () {
mOutArcPaint = new Paint();
mOutArcPaint.setColor(Color.RED);
mOutArcPaint.setStrokeWidth(ARC_WIDTH);
mOutArcPaint.setStyle(Paint.Style.STROKE);
mOutArcPaint.setAntiAlias(true );
mInnerCirclePaint = new Paint();
mInnerCirclePaint.setAntiAlias(true );
mInnerCirclePaint.setColor(Color.GRAY);
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true );
mTextPaint.setColor(Color.WHITE);
mTextPaint.setTextSize(TEXT_SIZE);
mMeasureTextWidth = mTextPaint.measureText(TEXT);
mInnerCircleDoubleRadius = mMeasureTextWidth + 2 * TEXT_PADDING;
mOutArcDoubleRadius = mInnerCircleDoubleRadius + 2 * ARC_WIDTH;
mRectF = new RectF(0 + ARC_WIDTH / 2 , 0 + ARC_WIDTH / 2 ,
mOutArcDoubleRadius - ARC_WIDTH / 2 , mOutArcDoubleRadius - ARC_WIDTH / 2 );
mHandler = new Handler() {
@Override
public void handleMessage (Message msg) {
super .handleMessage(msg);
mCurcentTime += 100 ;
if (mCurcentTime >= mTotalTime) {
mCurcentTime = mTotalTime;
invalidate();
if (mOnSkipListener!=null ){
mOnSkipListener.onSkip();
}
Toast.makeText(getContext(), "我要关闭该页面了" , Toast.LENGTH_SHORT).show();
return ;
}
invalidate();
mHandler.sendEmptyMessageDelayed(0 , 100 );
}
};
}
@Override
public boolean onTouchEvent (MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
setAlpha(0.5 f);
break ;
case MotionEvent.ACTION_UP:
setAlpha(1 f);
mHandler.removeCallbacksAndMessages(null );
Toast.makeText(getContext(), "关闭该页面" , Toast.LENGTH_SHORT).show();
if (mOnSkipListener!=null ){
mOnSkipListener.onSkip();
}
break ;
default :
break ;
}
return true ;
}
public void start () {
start(3000 );
}
public void start (int totalTime) {
mTotalTime = totalTime*10 ;
mHandler.sendEmptyMessageDelayed(0 , 100 );
}
@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
super .onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
switch (widthMode) {
case MeasureSpec.EXACTLY:
case MeasureSpec.AT_MOST:
widthSize = Math.min(widthSize, (int ) mOutArcDoubleRadius);
break ;
}
switch (heightMode) {
case MeasureSpec.EXACTLY:
case MeasureSpec.AT_MOST:
heightSize = Math.min(heightSize, (int ) mOutArcDoubleRadius);
break ;
}
int min = Math.min(widthSize, heightSize);
setMeasuredDimension(min, min);
}
private int mCurcentTime = 0 ;
private int mTotalTime = 3000 ;
@Override
protected void onDraw (Canvas canvas) {
super .onDraw(canvas);
int measuredHeight = getMeasuredHeight();
int measuredWidth = getMeasuredWidth();
canvas.save();
canvas.rotate(-90 , measuredWidth / 2 , measuredHeight / 2 );
float percent = mCurcentTime * 1 f / mTotalTime;
canvas.drawArc(mRectF, 0 , percent * 360 , false , mOutArcPaint);
canvas.restore();
canvas.drawCircle(measuredWidth / 2 , measuredHeight / 2 , mInnerCircleDoubleRadius / 2 , mInnerCirclePaint);
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
float ascent = fontMetrics.ascent;
float descent = fontMetrics.descent;
float top = fontMetrics.top;
float bottom = fontMetrics.bottom;
int baseLine = (int ) (measuredHeight / 2 - (top + bottom) / 2 );
canvas.drawText(TEXT, measuredWidth / 2 - mMeasureTextWidth / 2 , baseLine, mTextPaint);
}
private OnSkipListener mOnSkipListener;
public void setOnSkipListener (OnSkipListener onSkipListener){
mOnSkipListener = onSkipListener;
}
public interface OnSkipListener {
void onSkip();
}
}
后台下载图片的IntentService
public class DownloadPicService extends IntentService {
public static final String DOWNLOAD_PIC = "download_pic" ;
public DownloadPicService () {
super ("DownloadPicService" );
}
@Override
protected void onHandleIntent (@Nullable Intent intent) {
AdsBean adsBean = (AdsBean) intent.getSerializableExtra(DOWNLOAD_PIC);
ArrayList<AdItemBean> ads = adsBean.getAds();
OkHttpClient okHttpClient = new OkHttpClient();
for (int i = 0 ; i < ads.size(); i++) {
AdItemBean adItemBean = ads.get(i);
final String picUrl = adItemBean.getRes_url()[0 ];
File file = new File(getExternalCacheDir(), HashUtil.getHashCodeFileName(picUrl));
if (file.exists()&&file.length()>0 ){
Log.e(getClass().getSimpleName() + "xmg" , "onHandleIntent: " + "该图片已经存在,不再下载" );
continue ;
}
Request request = new Request.Builder().url(picUrl).build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure (Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse (Call call, Response response) throws IOException {
if (!response.isSuccessful()){
onFailure(call,new IOException("响应失败" ));
}
InputStream inputStream = response.body().byteStream();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
File file = new File(getExternalCacheDir(), HashUtil.getHashCodeFileName(picUrl));
FileOutputStream fileOutputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG,100 ,fileOutputStream);
}
});
}
}
}
KingTv
高仿全民直播(全民TV),项目采用 MVP + RXJava + Retrofit + OKHttp + Material Design + Dagger2 + Base + Glide + GreenDao构建。
https: //github.com /jenly1314/KingTV.git
public abstract class CustomFragmentPagerAdapter extends PagerAdapter {
private static final String TAG = CustomFragmentPagerAdapter.class.getSimpleName();
private final FragmentManager mFragmentManager;
private FragmentTransaction mCurTransaction;
private Fragment mCurrentPrimaryItem;
public CustomFragmentPagerAdapter (FragmentManager fm) {
mFragmentManager = fm;
}
public abstract Fragment getItem (int position);
@Override
public void startUpdate (ViewGroup container) {
if (container.getId() == View.NO_ID) {
throw new IllegalStateException("ViewPager with adapter " + this + " requires a view id" );
}
}
@Override
public Object instantiateItem (ViewGroup container, int position) {
if (mCurTransaction == null ) {
mCurTransaction = mFragmentManager.beginTransaction();
}
Fragment fragment = getItem(position);
Log.i(TAG, "Adding fragment item #" + position + ": f=" + fragment);
fragment.setMenuVisibility(false );
fragment.setUserVisibleHint(false );
mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), getItemId(position)));
return fragment;
}
@Override
public void destroyItem (ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
if (mCurTransaction == null ) {
mCurTransaction = mFragmentManager.beginTransaction();
}
Log.i(TAG, "Removing fragment #" + position + ": f=" + fragment + " v=" + fragment.getView());
mCurTransaction.remove(fragment);
}
@Override
public void setPrimaryItem (ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null ) {
mCurrentPrimaryItem.setMenuVisibility(false );
mCurrentPrimaryItem.setUserVisibleHint(false );
}
if (fragment != null ) {
fragment.setMenuVisibility(true );
fragment.setUserVisibleHint(true );
}
mCurrentPrimaryItem = fragment;
}
}
public void commitUpdate () {
if (mCurTransaction != null ) {
mCurTransaction.commitNowAllowingStateLoss();
mCurTransaction = null ;
}
}
@Override
public boolean isViewFromObject (View view, Object object) {
return ((Fragment) object).getView() == view;
}
protected String makeFragmentName (int viewId, long id) {
return "android:switcher:" + viewId + ":" + id;
}
protected long getItemId (int position) {
return position;
}
}
public class MainActivity extends AppCompatActivity {
ViewPager mViewPager;
List<String> mListContent = new ArrayList<>();
Fragment mCurrentFragment;
CustomFragmentPagerAdapter mAdapter;
@Override
protected void onCreate (Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for (int i = 0 ; i < 30 ; i++) {
mListContent.add(String.valueOf(i));
}
mViewPager = (ViewPager) findViewById(R.id.id_view_pager);
mViewPager.setAdapter(mAdapter = new CustomFragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public int getCount () {
return mListContent.size();
}
@Override
public Fragment getItem (int position) {
CustomFragment fragment = new CustomFragment();
Bundle bundle = new Bundle();
bundle.putString(CustomFragment.BUNDLE_KEY, "" + position);
fragment.setArguments(bundle);
return fragment;
}
@Override
public void setPrimaryItem (ViewGroup container, int position, Object object) {
super .setPrimaryItem(container, position, object);
if (mCurrentFragment == null ) {
commitUpdate();
}
mCurrentFragment = (Fragment) object;
}
@Override
public int getItemPosition (Object object) {
return PagerAdapter.POSITION_NONE;
}
});
mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageScrollStateChanged (int state) {
super .onPageScrollStateChanged(state);
if (state == ViewPager.SCROLL_STATE_IDLE) {
mAdapter.commitUpdate();
}
}
});
}
}
处理屏幕的旋转
public void clickFullScreen (){
if (isLandscape()){
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}else {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
<activity android:name =".MainActivity"
android:configChanges ="keyboardHidden|orientation|screenSize"
android:windowSoftInputMode ="stateHidden|stateUnchanged" />
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged (newConfig)
if(isLandscape()){
llRoomChat.setVisibility (View.GONE )
ivFullScreen.setVisibility (View.GONE )
}else{
llRoomChat.setVisibility (View.VISIBLE )
ivFullScreen.setVisibility (View.VISIBLE )
}
updateVideoLayoutParams()
}
TabLayout
public class ViewPagerFragmentAdapter extends FragmentPagerAdapter {
private List<Fragment> listData;
private List<CharSequence> listTitle;
public ViewPagerFragmentAdapter (FragmentManager fm, List<Fragment> listData){
this (fm,listData,null );
}
public ViewPagerFragmentAdapter (FragmentManager fm, List<Fragment> listData, List<CharSequence> listTitle) {
super (fm);
this .listData = listData;
this .listTitle = listTitle;
}
public List<Fragment> getListData () {
return listData;
}
public void setListData (List<Fragment> listData) {
this .listData = listData;
}
public List<CharSequence> getListTitle () {
return listTitle;
}
public void setListTitle (List<CharSequence> listTitle) {
this .listTitle = listTitle;
}
@Override
public Fragment getItem (int position) {
return listData==null ? null : listData.get(position) ;
}
@Override
public int getCount () {
return listData == null ? 0 : listData.size();
}
@Override
public CharSequence getPageTitle (int position) {
if (listTitle!=null && listTitle.size()!=0 ){
return listTitle.get(position);
}
return super .getPageTitle(position);
}
}
viewPagerFragmentAdapter = new ViewPagerFragmentAdapter(getFragmentManager(), listFragment, listTitles);
tabLayout .setupWithViewPager(viewPager);
tabLayout .addOnTabSelectedListener();
保持屏幕常亮
Activity.getWindow ().addFlags (WindowManager.LayoutParams .FLAG _KEEP_SCREEN_ON)
EasyRecyclerView自适应高度
<com.jude.easyrecyclerview.EasyRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
item布局中
把网格布局item中的父控件和imageview全部设置设置成了match_parent,而更换成一个固定值后,成功了!
@Override
public MyViewHolder onCreateViewHolder (ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.item_grid, parent, false );
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((dm.widthPixels - dip2px(20 )) / 3 , (dm.widthPixels - dip2px(20 )) / 3 );
view.setLayoutParams(lp);
return new MyViewHolder(view);
}
父布局加上 android:focusable="true" ; android:focusableInTouchMode="true" ;
抓取Bugly捕获的信息
CrashReport.postCatchedException (e)
public interface CrashHandler{
void uncaughtException(Thread t,Throwable e);
}
mCrashHandler = crashHandler;
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run () {
for (;;) {
try {
Looper.loop();
} catch (Throwable e) {
if (mCrashHandler != null ) {
mCrashHandler.uncaughtException(Looper.getMainLooper().getThread(), e);
}
}
}
}
});
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException (Thread t, Throwable e) {
if (mCrashHandler!=null ){
mCrashHandler.uncaughtException(t,e);
}
}
});
线程池的封装
public class ThreadPoolManager {
private static ThreadPoolProxy mInstance;
public static ThreadPoolProxy getInstance () {
if (mInstance == null ) {
synchronized (ThreadPoolManager.class) {
if (mInstance == null ) {
mInstance = new ThreadPoolProxy(2 , 5 );
}
}
}
return mInstance;
}
public static class ThreadPoolProxy {
private ThreadPoolExecutor mThreadPoolExecutor;
public ThreadPoolProxy (int corePoolSize, int maximumPoolSize) {
initThreadPoolExecutor(corePoolSize, maximumPoolSize);
}
private void initThreadPoolExecutor (int corePoolSize, int maximumPoolSize) {
if (mThreadPoolExecutor == null ) {
BlockingDeque<Runnable> workQueue = new LinkedBlockingDeque<>();
ThreadFactory threadFactory = Executors.defaultThreadFactory();
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
mThreadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 0 , TimeUnit.MICROSECONDS, workQueue, threadFactory, handler);
}
}
public void submit (Runnable task) {
if (mThreadPoolExecutor != null ) {
mThreadPoolExecutor.submit(task);
}
}
public void execute (Runnable task) {
if (mThreadPoolExecutor != null ) {
mThreadPoolExecutor.execute(task);
}
}
public void remove (Runnable task) {
if (mThreadPoolExecutor != null ) {
mThreadPoolExecutor.remove(task);
}
}
}
}
<RadioGroup
android:orientation="horizontal"
android:padding="6dp"
android:checkedButton="@+ id/rbHome" >
<RadioButton
android:id="@+ id/rbHome"
android:button="@null "
android:drawablePadding="4dp"
android:drawableTop="@drawable /btn_tabbar_wode_selector" />
<RadioButton
android:id="@+ id/rbLive"
android:button="@null "
android:drawablePadding="4dp"
android:drawableTop="@drawable /btn_tabbar_wode_selector" />
<RadioButton
android:id="@+ id/rbFollw"
android:button="@null "
android:drawablePadding="4dp"
android:drawableTop="@drawable /btn_tabbar_wode_selector" >
<RadioButton
android:id="@+ id/rbMe"
android:button="@null "
android:drawablePadding="4dp"
android:drawableTop="@drawable /btn_tabbar_wode_selector" />
</RadioGroup>
@OnClick({com .king .tv .R .id .rbHome , com .king .tv .R .id .rbLive , com .king .tv .R .id .rbFollw , com .king .tv .R .id .rbMe })
public void onClick(View view) {
switch (view.getId ()) {
case com .king .tv .R .id .rbHome :
showHomeFragment()
break
case com .king .tv .R .id .rbLive :
showLiveFragment()
break
case com .king .tv .R .id .rbFollw :
showFollowFragment()
break
case com .king .tv .R .id .rbMe :
showMineFragment()
break
}
}
public void showHomeFragment (){
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
hideAllFragment(fragmentTransaction);
if (homeFragment == null ){
homeFragment = HomeFragment.newInstance();
fragmentTransaction.add(com.king.tv.R.id.fragmentContent,homeFragment);
}
commitShowFragment(fragmentTransaction,homeFragment);
}
public void hideAllFragment (FragmentTransaction fragmentTransaction){
hideFragment(fragmentTransaction,homeFragment);
hideFragment(fragmentTransaction,liveFragment);
hideFragment(fragmentTransaction,followFragment);
hideFragment(fragmentTransaction,mineFragment);
}
private void hideFragment (FragmentTransaction fragmentTransaction,Fragment fragment){
if (fragment!=null ){
fragmentTransaction.hide(fragment);
}
}
public void commitShowFragment (FragmentTransaction fragmentTransaction,Fragment fragment){
fragmentTransaction.show(fragment);
fragmentTransaction.commit();
}
KingsGirls
项目采用RXJava + Retrofit + OKHttp + Material Design + Base + Glide构建,数据来自gank.io 。是一款以瀑布流的形式展示美女福利的App
https: //github.com /jenly1314/KingsGirls.git
半透明状态栏
if (Build.VERSION .SDK _INT >= Build.VERSION _CODES.KITKAT ) {
Window window = getWindow()
window.setFlags (WindowManager.LayoutParams .FLAG _TRANSLUCENT_STATUS
,WindowManager.LayoutParams .FLAG _TRANSLUCENT_STATUS)
}
半透明虚拟按键
if (Build.VERSION .SDK _INT >= Build.VERSION _CODES.KITKAT ) {
Window window = getWindow()
window.setFlags (WindowManager.LayoutParams .FLAG _TRANSLUCENT_NAVIGATION
,WindowManager.LayoutParams .FLAG _TRANSLUCENT_NAVIGATION)
}
Glide缓存策略
Glide.with (context)
.load (url).error (R.drawable .ic _welcome).crossFade ()
//缓存策略,只保存源文件到本地
.diskCacheStrategy (DiskCacheStrategy.SOURCE )
.into (iv)
获取屏幕的DecorView ContentView
//DecorView
ViewGroup view = (ViewGroup)activity.getWindow ().getDecorView ()
//ContentView
FrameLayout content = (FrameLayout)view.findViewById (android.R .id .content )
//activity的根布局
content.getChildAt (0 )
对findViewById进行抽取
protected <T extends View> T findView (int resId){
return (T)findViewById(resId);
}
TextView=findView(R.id.tv);
安装apk文件
public static void installApk (Context context,String path){
installApk(context,new File(path));
}
public static void installApk (Context context,File file){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uriData = Uri.fromFile(file);
String type = "application/vnd.android.package-archive" ;
intent.setDataAndType(uriData, type);
context.startActivity(intent);
}
权限相关
public static boolean checkSelfPermission (Context context, @NonNull String permission){
return ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED;
}
public static void requestPermission (Activity activity, @NonNull String permission, int requestCode){
ActivityCompat.requestPermissions(activity,new String[]{permission}, requestCode);
}
public static void shouldShowRequestPermissionRationale (Activity activity, @NonNull String permission){
ActivityCompat.shouldShowRequestPermissionRationale(activity,permission);
}
Coordinator使用相关
<android.support .design .widget .AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" >
<android.support .v 7.widget .Toolbar
android:id="@+id/toolBar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
android:title="@string/app_name"
app:layout_collapseMode="pin"
//被上拉隐藏
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:titleTextColor="@color/white" />
<android.support .design .widget .TabLayout
//没有设置app:layout_scrollFlags,不会被上拉隐藏
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
app:tabIndicatorColor="@color/red"
app:tabIndicatorHeight="3dp"
app:tabMinWidth="60dp"
app:tabMode="scrollable"
app:tabSelectedTextColor="@color/red"
app:tabTextAppearance="@style/TabLayoutTextAppearance"
app:tabTextColor="@color/black" />
</android.support .design .widget .AppBarLayout >
在style中去除actionbar&自定义lv分割线样式
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar" >
<item name="windowActionBar" >false </item >
<item name="windowNoTitle" >true </item >
<item name="android:listDivider" >@drawable/list_divider</item >
</style>
Fragment的工厂方法,从而实现在Fragment创建时输入一些数据
public static GirlsFragment newInstance (LayoutType layoutType) {
Bundle args = new Bundle();
GirlsFragment fragment = new GirlsFragment();
fragment.setArguments(args);
fragment.layoutType = layoutType;
return fragment;
}
Recyclerview瀑布流时第一行有空白的问题的解决
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2 ,StaggeredGridLayoutManager.VERTICAL);
staggeredGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
recyclerView.setLayoutManager(staggeredGridLayoutManager);
recyclerView.getRecyclerView().addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged (RecyclerView recyclerView, int newState) {
super .onScrollStateChanged(recyclerView, newState);
staggeredGridLayoutManager.invalidateSpanAssignments();
}
});
从被点击的view以缩放图的形式打开一个act的过渡动画
ActivityOptionsCompat activityOptionsCompat =ActivityOptionsCompat.makeScaleUpAnimation (source
,source.getWidth ()/2 ,source.getHeight ()/2 ,0 ,0 )
ActivityCompat.startActivity (getActivity(),intent,activityOptionsCompat.toBundle ())
Retrofit模版
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.6'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
public class APIRetrofit {
private static Retrofit mInstance;
private static OkHttpClient mOKHttpClient;
public static Retrofit getInstance () {
if (mInstance == null ) {
synchronized (APIRetrofit.class) {
if (mInstance == null ) {
mInstance = new Retrofit.Builder()
.baseUrl("http://gank.io" )
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(getOkHttpClient())
.build();
}
}
}
return mInstance;
}
private static OkHttpClient getOkHttpClient () {
if (mInstance == null ) {
synchronized (APIRetrofit.class) {
if (mOKHttpClient == null ) {
mOKHttpClient = new OkHttpClient.Builder()
.connectTimeout(10 , TimeUnit.SECONDS)
.readTimeout(10 , TimeUnit.SECONDS)
.writeTimeout(10 , TimeUnit.SECONDS)
.build();
}
}
}
return mOKHttpClient;
}
}
public interface APIService {
/**
* @param type 可选参数: Android | iOS | 休息视频 | 福利 | 拓展资源 | 前端 | 瞎推荐 | App
*/
@GET ("api/data/{type}/{count}/{page}" )
Observable<GirlResult> getGirs(@Path ("type" ) String type, @Path ("count" ) int count, @Path ("page" ) int page);
}
APIRetrofit.getInstance ()
.create (APIService.class )
.getGirs ("福利" , 1 , n)
.subscribeOn (Schedulers.io ())
.observeOn (AndroidSchedulers.mainThread ())
.subscribe (new Observer<GirlResult>() {
@Override
public void onCompleted() {
Logger.d ("onCompleted" )
}
@Override
public void onError(Throwable e) {
Logger.d ("onError" )
}
@Override
public void onNext(GirlResult girlResult) {
Logger.d (girlResult)
if (girlResult.isError ()) {
mImageView.setImageResource (R.mipmap .ic _launcher_round)
}else{
List<GirlResult.Girl > results = girlResult.getResults ()
GirlResult.Girl girl = results.get (0 )
String url = girl.getUrl ()
Picasso.with (MainActivity.this )
.load (url)
.into (mImageView)
}
}
})
TabLayout
<android.support.design.widget.TabLayout
android:id="@+ id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color /white"
app:tabIndicatorColor="@color /red"
app:tabIndicatorHeight="3dp"
app:tabMinWidth="60dp"
app:tabMode="scrollable"
app:tabSelectedTextColor="@color /red"
app:tabTextAppearance="@style /TabLayoutTextAppearance"
app:tabTextColor="@color /black" />
<style name = "TabLayoutTextAppearance" parent="TextAppearance.AppCompat.Widget.ActionBar.Title" >
<item name ="android:textSize" >16 sp</item >
<item name ="android:textAllCaps" >false </item >
</style>
tabLayout .setupWithViewPager(viewPager);
dp sp px转换工具类
public class DensityUtil {
private DensityUtil (){
throw new AssertionError();
}
public static int dp2px (Context context,float dpVal){
return (int ) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpVal,getDisplayMetrics(context));
}
public static int sp2px (Context context,float spVal){
return (int )TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,spVal,getDisplayMetrics(context));
}
public static int px2dp (Context context,float pxVal){
return (int ) (pxVal / getDisplayMetrics(context).density + 0.5 f);
}
public static int px2sp (Context context,float pxVal){
return (int ) (pxVal / getDisplayMetrics(context).scaledDensity + 0.5 f);
}
public static DisplayMetrics getDisplayMetrics (Context context){
return context.getResources().getDisplayMetrics();
}
}
重构
提示等待的进度条的抽取
public class BaseProgressDialog extends Dialog {
public static BaseProgressDialog newInstance (Context context){
return new BaseProgressDialog(context);
}
public BaseProgressDialog (Context context) {
this (context,R.style.progress_dialog);
initUI();
}
public BaseProgressDialog (Context context, int themeResId) {
super (context, themeResId);
initUI();
}
protected BaseProgressDialog (Context context, boolean cancelable, OnCancelListener cancelListener) {
super (context, cancelable, cancelListener);
initUI();
}
private void initUI (){
setContentView(new ProgressBar(getContext()));
getWindow().getAttributes().gravity = Gravity.CENTER;
setCanceledOnTouchOutside(false );
}
}
BaseAcitivity
public interface BaseInterface {
public static final int NONE = -1 ;
public static final int REQUEST_CODE = 0X01 ;
public static final int RESULT_OK = Activity.RESULT_OK;
public static final int RESULT_CANCELED = Activity.RESULT_CANCELED;
public static final String KEY_ID = "key_id" ;
public static final String KEY_TITLE = "key_title" ;
public static final String KEY_URL = "key_url" ;
public static final String KEY_SERIALIZABLE = "key_serializable" ;
public static final String KEY_OBJECT = "key_object" ;
public static final String KEY_FRAGMENT = "key_fragment" ;
public abstract void initUI ();
public abstract void initData ();
public abstract void addListeners ();
}
public abstract class BaseActivity extends AppCompatActivity implements BaseInterface {
protected Context context = this ;
private Dialog dialog;
private BaseProgressDialog progressDialog;
protected boolean isStop;
protected int curPage;
@Override
protected void onCreate (Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
curPage = 1 ;
initUI();
initData();
addListeners();
}
@Override
protected void onResume () {
super .onResume();
isStop = false ;
}
@Override
protected void onStop () {
super .onStop();
isStop = true ;
dismissProgressDialog();
}
@Override
protected void onDestroy () {
super .onDestroy();
dismissDialog();
}
public static View getContentView (Activity activity){
ViewGroup view = (ViewGroup)activity.getWindow().getDecorView();
FrameLayout content = (FrameLayout)view.findViewById(android.R.id.content);
return content.getChildAt(0 );
}
protected View inflate (@LayoutRes int id){
return inflate(id,null );
}
protected View inflate (@LayoutRes int id, @Nullable ViewGroup root){
return LayoutInflater.from(context).inflate(id,root);
}
protected <T extends View> T findView (int resId){
return (T)findViewById(resId);
}
protected void setOnClickListener (@IdRes int id,View.OnClickListener onClicklistener){
findViewById(id).setOnClickListener(onClicklistener);
}
protected Intent getIntent (Class<?> cls){
return new Intent(context,cls);
}
protected Intent getIntent (Class<?> cls,int flags){
Intent intent = getIntent(cls);
intent.setFlags(flags);
return intent;
}
protected void startActivity (Class<?> cls){
startActivity(getIntent(cls));
}
protected void startActivity (Class<?> cls,int flags){
startActivity(getIntent(cls,flags));
}
protected void startActivityFinish (Class<?> cls){
startActivity(cls);
finish();
}
protected void startActivityFinish (Class<?> cls,int flags){
startActivity(cls,flags);
finish();
}
public void replaceFragment (@IdRes int resId,Fragment fragment){
replaceFragment(resId,fragment,false );
}
public void replaceFragment (@IdRes int resId, Fragment fragment, boolean isBackStack) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(resId, fragment);
if (isBackStack){
fragmentTransaction.addToBackStack(null );
}
fragmentTransaction.commit();
}
protected void showToast (@StringRes int resId){
if (resId != NONE)
ToastUtils.showToast(context,resId);
}
protected void showLongToast (@StringRes int resId){
ToastUtils.showToast(context,resId, Toast.LENGTH_LONG);
}
protected void showToast (CharSequence text){
ToastUtils.showToast(context,text);
}
protected void showLongToast (CharSequence text){
ToastUtils.showToast(context,text, Toast.LENGTH_LONG);
}
public boolean checkInput (TextView tv){
return checkInput(tv,NONE);
}
public boolean checkInput (TextView tv,@StringRes int resId){
return checkInput(tv,resId,false );
}
public boolean checkInput (TextView tv,@StringRes int resId,boolean isShake){
if (StringUtils.isBlank(tv.getText())){
if (isShake)
startShake(tv,resId);
else
showToast(resId);
return false ;
}
return true ;
}
public void startShake (View v,@StringRes int resId){
startShake(v);
showToast(resId);
}
public void startShake (View view){
view.startAnimation(AnimationUtils.loadAnimation(context,R.anim.shake));
}
public void hideInputMethod (EditText v) {
SystemUtils.hideInputMethod(context,v);
}
public void showInputMethod (EditText v) {
SystemUtils.showInputMethod(context,v);
}
public Dialog getProgressDialog () {
return progressDialog;
}
protected void showProgressDialog (){
showProgressDialog(new ProgressBar(context));
}
protected void showProgressDialog (@LayoutRes int resId){
showProgressDialog(LayoutInflater.from(context).inflate(resId,null ));
}
protected void showProgressDialog (View v){
dismissProgressDialog();
progressDialog = BaseProgressDialog.newInstance(context);
progressDialog.setContentView(v);
progressDialog.show();
}
protected void dismissProgressDialog (){
dismissDialog(progressDialog);
}
public Dialog getDialog () {
return dialog;
}
protected void showDialog (View contentView){
showDialog(context,contentView);
}
protected void showDialog (Context context,View contentView){
dismissDialog();
dialog = new Dialog(context,R.style.dialog);
dialog.setContentView(contentView);
dialog.setCanceledOnTouchOutside(false );
getDialogWindow(dialog);
dialog.show();
}
protected void dismissDialog (){
dismissDialog(dialog);
}
protected void dismissDialog (Dialog dialog){
if (dialog != null && dialog.isShowing()){
dialog.dismiss();
}
}
protected void getDialogWindow (Dialog dialog){
Window window = dialog.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
lp.width = (int )(getWidthPixels()*0.9 f);
lp.gravity= Gravity.CENTER;
window.setAttributes(lp);
}
protected void dismissDialogFragment (DialogFragment dialogFragment){
if (dialogFragment != null ){
dialogFragment.dismiss();
}
}
public void showDialogFragment (DialogFragment dialogFragment){
String tag = dialogFragment.getTag() !=null ? dialogFragment.getTag() : dialogFragment.getClass().getSimpleName();
showDialogFragment(dialogFragment,tag);
}
public void showDialogFragment (DialogFragment dialogFragment,String tag) {
dialogFragment.show(getSupportFragmentManager(),tag);
}
protected void asyncThread (Runnable runnable){
new Thread(runnable).start();
}
protected DisplayMetrics getDisplayMetrics (){
return getResources().getDisplayMetrics();
}
protected int getWidthPixels (){
return getDisplayMetrics().widthPixels;
}
protected int getHeightPixels (){
return getDisplayMetrics().heightPixels;
}
}
ListViewAdapter
public abstract class AbstractAdapter<T> extends BaseAdapter{
private Context context;
private List<T> listData;
private LayoutInflater layoutInflater;
public AbstractAdapter (Context context,List<T> listData){
this .context = context;
this .listData = listData;
layoutInflater = LayoutInflater.from (context);
}
@Override
public int getCount () {
return listData==null ? 0 :listData.size();
}
@Override
public Object getItem (int position) {
return listData==null ? null :listData.get (position);
}
@Override
public long getItemId (int position) {
return position;
}
public List<T> getListData () {
return listData;
}
public void setListData (List<T> listData) {
this .listData = listData;
}
public Context getContext (){
return context;
}
public LayoutInflater getLayoutInflater (){
return layoutInflater;
}
public View inflate (@LayoutRes int layoutId,ViewGroup parent,boolean attachToRoot){
return layoutInflater.inflate(layoutId,parent,attachToRoot);
}
}
public abstract class HolderAdapter<T,H> extends AbstractAdapter<T>{
public HolderAdapter (Context context, List<T> listData) {
super(context, listData);
}
@Override
public View getView (int position, View convertView, ViewGroup parent) {
H holder = null ;
T t = getListData().get (position);
if (convertView==null ){
convertView = buildConvertView(getLayoutInflater(),t,position,parent);
holder = buildHolder(convertView,t,position);
convertView.setTag(holder);
}else {
holder = (H)convertView.getTag();
}
bindViewDatas(holder,t,position);
return convertView;
}
public abstract View buildConvertView (LayoutInflater layoutInflater,T t,int position, ViewGroup parent);
public abstract H buildHolder (View convertView,T t,int position);
public abstract void bindViewDatas (H holder,T t,int position);
}
public abstract class ViewHolderAdapter <T > extends HolderAdapter <T ,ViewHolder > {
public ViewHolderAdapter(Context context, List<T> listData) {
super (context, listData);
}
@Override
public ViewHolder buildHolder(View convertView, T t, int position) {
return new ViewHolder(convertView);
}
}
RecyclerViewAdapter的抽取
public abstract class HolderRecyclerAdapter<T,H extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<H>{
private Context context;
private List<T> listData;
private LayoutInflater layoutInflater;
private OnItemClicklistener mOnItemClicklistener;
public HolderRecyclerAdapter (Context context, List<T> listData){
super();
this .context = context;
this .listData = listData;
this .layoutInflater = LayoutInflater.from (context);
}
@Override
public int getItemCount () {
return listData==null ? 0 :listData.size();
}
public List<T> getListData () {
return listData;
}
public void setListData (List<T> listData) {
this .listData = listData;
}
@Override
public H onCreateViewHolder (ViewGroup parent, int viewType) {
View itemView = buildConvertView(layoutInflater,parent,viewType);
return buildHolder(itemView,viewType);
}
@Override
public void onBindViewHolder (H holder, final int position) {
T t = position<listData.size() ? listData.get (position) : null ;
bindViewDatas(holder,t,position);
if (this .mOnItemClicklistener!=null ){
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick (View v) {
mOnItemClicklistener.onItemClick(v,position);
}
});
}
}
public interface OnItemClicklistener{
public void onItemClick (View v, int position);
}
public void setOnItemClicklistener (OnItemClicklistener onItemClicklistener){
this .mOnItemClicklistener = onItemClicklistener;
}
public LayoutInflater getLayoutInflater (){
return layoutInflater;
}
public View inflate (@LayoutRes int layoutId,ViewGroup parent,boolean attachToRoot){
return layoutInflater.inflate(layoutId,parent,attachToRoot);
}
public Context getContext (){
return context;
}
public abstract View buildConvertView (LayoutInflater layoutInflater,ViewGroup parent,int viewType);
public abstract H buildHolder (View convertView,int viewType);
public abstract void bindViewDatas (H holder,T t,int position);
}
Fragment的抽取
public abstract class BaseFragment extends Fragment implements BaseInterface {
protected Context context;
private Dialog dialog;
private BaseProgressDialog progressDialog;
protected ViewGroup container;
protected View rootView;
protected int curPage;
protected boolean isStop;
public ViewGroup getContainer (){
return container;
}
public View getActivityRootView (){
return getActivity().findViewById(android.R.id.content);
}
@Nullable
@Override
public View onCreateView (LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
context = getActivity();
this .container = container;
rootView = inflater.inflate(inflaterRootView(), container, false );
curPage = 1 ;
initUI();
initData();
addListeners();
if (rootView!=null )
return rootView;
return super .onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onResume () {
super .onResume();
isStop = false ;
}
@Override
public void onStop () {
super .onStop();
isStop = true ;
dismissProgressDialog();
}
@Override
public void onDestroy () {
super .onDestroy();
dismissDialog();
}
protected Intent getIntent (){
return getActivity().getIntent();
}
protected Intent getIntent (Class<?> cls){
return new Intent(context,cls);
}
protected Intent getIntent (Class<?> cls,int flags){
Intent intent = getIntent(cls);
intent.setFlags(flags);
return intent;
}
protected void startActivity (Class<?> cls){
startActivity(getIntent(cls));
}
protected void startActivity (Class<?> cls,int flags){
startActivity(getIntent(cls,flags));
}
protected void startActivityFinish (Class<?> cls){
startActivity(cls);
finish();
}
protected void startActivityFinish (Class<?> cls,int flags){
startActivity(cls,flags);
finish();
}
protected void finish (){
getActivity().finish();
}
protected void setResult (int resultCode){
setResult(resultCode,getIntent());
}
protected void setResult (int resultCode,Intent intent){
getActivity().setResult(resultCode,intent);
}
protected void setIntent (Intent newIntent){
getActivity().setIntent(newIntent);
}
@Override
public LayoutInflater getLayoutInflater (Bundle savedInstanceState) {
return super .getLayoutInflater(savedInstanceState);
}
protected View inflate (@LayoutRes int id){
return inflate(id,null );
}
protected View inflate (@LayoutRes int id, @Nullable ViewGroup root){
return LayoutInflater.from(context).inflate(id,root);
}
protected void setOnClickListener (@IdRes int id,View.OnClickListener onClicklistener){
findView(id).setOnClickListener(onClicklistener);
}
protected <T extends View> T findView (int resId){
return (T)rootView.findViewById(resId);
}
public void replaceChildFragment (@IdRes int resId, Fragment fragment) {
replaceFragment(getChildFragmentManager(),resId,fragment,false );
}
public void replaceFragment (@IdRes int resId, Fragment fragment){
replaceFragment(resId,fragment,false );
}
public void replaceFragment (@IdRes int resId, Fragment fragment, boolean isBackStack) {
replaceFragment(getFragmentManager(),resId,fragment,isBackStack);
}
public void replaceFragment (FragmentManager fragmentManager, @IdRes int resId, Fragment fragment, boolean isBackStack) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(resId, fragment);
if (isBackStack){
fragmentTransaction.addToBackStack(null );
}
fragmentTransaction.commit();
}
protected void showToast (@StringRes int resId){
if (resId != NONE)
ToastUtils.showToast(context,resId);
}
protected void showLongToast (@StringRes int resId){
if (resId != NONE)
ToastUtils.showToast(context,resId, Toast.LENGTH_LONG);
}
protected void showToast (CharSequence text){
ToastUtils.showToast(context,text);
}
protected void showLongToast (CharSequence text){
ToastUtils.showToast(context,text, Toast.LENGTH_LONG);
}
public boolean checkInput (TextView tv){
return checkInput(tv,NONE);
}
public boolean checkInput (TextView tv,@StringRes int resId){
return checkInput(tv,resId,false );
}
public boolean checkInput (TextView tv,@StringRes int resId,boolean isShake){
if (StringUtils.isBlank(tv.getText())){
if (isShake)
startShake(tv,resId);
else
showToast(resId);
return false ;
}
return true ;
}
public void startShake (View v,@StringRes int resId){
startShake(v);
showToast(resId);
}
public void startShake (View view){
view.startAnimation(AnimationUtils.loadAnimation(context,R.anim.shake));
}
public void hideInputMethod (final EditText v) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(),0 );
}
public void showInputMethod (final EditText v) {
v.requestFocus();
InputMethodManager imm = (InputMethodManager)context
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(v,0 );
}
public Dialog getProgressDialog () {
return progressDialog;
}
protected void showProgressDialog (){
showProgressDialog(new ProgressBar(context));
}
protected void showProgressDialog (@LayoutRes int resId){
showProgressDialog(LayoutInflater.from(context).inflate(resId,null ));
}
protected void showProgressDialog (View v){
dismissProgressDialog();
progressDialog = BaseProgressDialog.newInstance(context);
progressDialog.setContentView(v);
progressDialog.show();
}
public void showDialogFragment (DialogFragment dialogFragment){
String tag = dialogFragment.getTag() !=null ? dialogFragment.getTag() : dialogFragment.getClass().getSimpleName();
showDialogFragment(dialogFragment,tag);
}
public void showDialogFragment (DialogFragment dialogFragment,String tag) {
dialogFragment.show(getFragmentManager(),tag);
}
protected void dismissDialogFragment (DialogFragment dialogFragment){
if (dialogFragment != null ){
dialogFragment.dismiss();
}
}
protected void showDialog (View contentView){
showDialog(context,contentView);
}
protected void showDialog (Context context,View contentView){
dismissDialog();
dialog = new Dialog(context,R.style.dialog);
dialog.setContentView(contentView);
dialog.setCanceledOnTouchOutside(false );
getDialogWindow(dialog);
dialog.show();
}
protected void getDialogWindow (Dialog dialog){
Window window = dialog.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
lp.width = (int )(getWidthPixels()*0.9 f);
window.setAttributes(lp);
}
public Dialog getDialog () {
return dialog;
}
protected void dismissProgressDialog (){
dismissDialog(progressDialog);
}
protected void dismissDialog (){
dismissDialog(dialog);
}
protected void dismissDialog (Dialog dialog){
if (dialog != null && dialog.isShowing()){
dialog.dismiss();
}
}
protected void asyncThread (Runnable runnable){
new Thread(runnable).start();
}
protected DisplayMetrics getDisplayMetrics (){
return getResources().getDisplayMetrics();
}
protected int getWidthPixels (){
return getDisplayMetrics().widthPixels;
}
protected int getHeightPixels (){
return getDisplayMetrics().heightPixels;
}
@LayoutRes
public abstract int inflaterRootView ();
}
public class ViewPagerFragmentAdapter extends FragmentPagerAdapter {
private List<Fragment> listData;
private List<CharSequence> listTitle;
public ViewPagerFragmentAdapter (FragmentManager fm, List<Fragment> listData){
this (fm,listData,null );
}
public ViewPagerFragmentAdapter (FragmentManager fm, List<Fragment> listData, List<CharSequence> listTitle) {
super (fm);
this .listData = listData;
this .listTitle = listTitle;
}
public List<Fragment> getListData () {
return listData;
}
public void setListData (List<Fragment> listData) {
this .listData = listData;
}
public List<CharSequence> getListTitle () {
return listTitle;
}
public void setListTitle (List<CharSequence> listTitle) {
this .listTitle = listTitle;
}
@Override
public Fragment getItem (int position) {
return listData==null ? null : listData.get(position) ;
}
@Override
public int getCount () {
return listData == null ? 0 : listData.size();
}
@Override
public CharSequence getPageTitle (int position) {
if (listTitle!=null && listTitle.size()!=0 ){
return listTitle.get(position);
}
return super .getPageTitle(position);
}
}